Line data Source code
1 : /*
2 : Zipios -- a small C++ library that provides easy access to .zip files.
3 :
4 : Copyright (c) 2019-2022 Made to Order Software Corp. All Rights Reserved
5 :
6 : This library is free software; you can redistribute it and/or
7 : modify it under the terms of the GNU Lesser General Public
8 : License as published by the Free Software Foundation; either
9 : version 2.1 of the License, or (at your option) any later version.
10 :
11 : This library is distributed in the hope that it will be useful,
12 : but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : Lesser General Public License for more details.
15 :
16 : You should have received a copy of the GNU Lesser General Public
17 : License along with this library; if not, write to the Free Software
18 : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 : */
20 :
21 : /** \file
22 : * \brief Implementation of the zipios::DOSDateTime class.
23 : *
24 : * This file is the implementation of the zipios::DOSDateTime class
25 : * which converts dates between Unix timestamps and DOS Date Time
26 : * timestamps.
27 : *
28 : * Keep in mind that the dates in a zip file use your local time,
29 : * whatever that is at the time you create the file. The get/set Unix
30 : * timestamp functions adjust the date to UTC as required.
31 : *
32 : * \sa https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-dosdatetimetofiletime
33 : */
34 :
35 : #include "zipios/dosdatetime.hpp"
36 :
37 : #include "zipios/zipiosexceptions.hpp"
38 :
39 :
40 : namespace zipios
41 : {
42 :
43 :
44 : DOSDateTime::dosdatetime_t const DOSDateTime::g_min_dosdatetime; // Jan 1, 1980 00:00:00
45 : DOSDateTime::dosdatetime_t const DOSDateTime::g_max_dosdatetime; // Dec 31, 2107 23:59:59
46 :
47 :
48 :
49 :
50 : /** \brief Union used to convert the uint32_t to fields and vice versa.
51 : *
52 : * This union is used by the functions below to convert the basic
53 : * uint32_t dosdatetime_t values in a list of 6 fields.
54 : */
55 : union dosdatetime_convert_t
56 : {
57 : DOSDateTime::dosdatetime_t m_dosdatetime;
58 : struct fields
59 : {
60 : #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
61 : DOSDateTime::dosdatetime_t m_year : 7; // add 1980
62 : DOSDateTime::dosdatetime_t m_month : 4; // 1 to 12
63 : DOSDateTime::dosdatetime_t m_mday : 5; // 1 to 31
64 : DOSDateTime::dosdatetime_t m_hour : 5;
65 : DOSDateTime::dosdatetime_t m_minute : 6;
66 : DOSDateTime::dosdatetime_t m_second : 5; // WARNING: the precision is every 2 seconds (0, 2, 4, etc.)
67 : #else
68 : DOSDateTime::dosdatetime_t m_second : 5; // WARNING: the precision is every 2 seconds (0, 2, 4, etc.)
69 : DOSDateTime::dosdatetime_t m_minute : 6;
70 : DOSDateTime::dosdatetime_t m_hour : 5;
71 : DOSDateTime::dosdatetime_t m_mday : 5; // 1 to 31
72 : DOSDateTime::dosdatetime_t m_month : 4; // 1 to 12
73 : DOSDateTime::dosdatetime_t m_year : 7; // add 1980
74 : #endif
75 : } m_fields;
76 : };
77 :
78 :
79 :
80 : namespace
81 : {
82 :
83 : /** \brief Number of days in a month.
84 : *
85 : * This table is used in the daysInMonth() function to determine the number
86 : * of days in the month. It is ignored if the month is February.
87 : */
88 : int const g_days_in_month[12] = {
89 : /* Jan */ 31,
90 : /* Feb */ 0, // special handling
91 : /* Mar */ 31,
92 : /* Apr */ 30,
93 : /* May */ 31,
94 : /* Jun */ 30,
95 : /* Jul */ 31,
96 : /* Aug */ 31,
97 : /* Sep */ 30,
98 : /* Oct */ 31,
99 : /* Nov */ 30,
100 : /* Dec */ 31
101 : };
102 :
103 :
104 : int const g_ydays[12] = {
105 : /* Jan */ 0,
106 : /* Feb */ 31,
107 : /* Mar */ 31 + 0, // special handling
108 : /* Apr */ 31 + 0 + 31,
109 : /* May */ 31 + 0 + 31 + 30,
110 : /* Jun */ 31 + 0 + 31 + 30 + 31,
111 : /* Jul */ 31 + 0 + 31 + 30 + 31 + 30,
112 : /* Aug */ 31 + 0 + 31 + 30 + 31 + 30 + 31,
113 : /* Sep */ 31 + 0 + 31 + 30 + 31 + 30 + 31 + 31,
114 : /* Oct */ 31 + 0 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
115 : /* Nov */ 31 + 0 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
116 : /* Dec */ 31 + 0 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30
117 : };
118 :
119 :
120 : }
121 :
122 :
123 :
124 : /** \brief Check whether this DOS Date & Date is valid.
125 : *
126 : * This function verifies to see whether the DOS Date & Time it holds is
127 : * valid. By default, the value is set to zero which represents an invalid
128 : * date (_not set_).
129 : *
130 : * \note
131 : * Remember that Zip file Date & Time are saved in an old MS-DOS format
132 : * which did not respect UTC. It instead represents local time. This
133 : * function returns true when the local time is valid, since the same
134 : * time will be shared around the globe, it will always be considered
135 : * valid, but the Unix timestamp can look like a mismatch (the minimum
136 : * and maximum possible time stamps represented in a Unix time_t variable
137 : * will vary depending on your timezone settings.)
138 : *
139 : * \return true if the date is considered valid (represents an actual date
140 : * and time).
141 : *
142 : * \sa daysInMonth()
143 : */
144 476369 : bool DOSDateTime::isValid() const
145 : {
146 : dosdatetime_convert_t conv;
147 476369 : conv.m_dosdatetime = m_dosdatetime;
148 476369 : return conv.m_fields.m_second < 30 // remember we only keep `sec / 2` in a DOS time field
149 476369 : && conv.m_fields.m_minute < 60
150 476369 : && conv.m_fields.m_hour < 24
151 476369 : && conv.m_fields.m_mday > 0
152 476187 : && conv.m_fields.m_mday <= daysInMonth()
153 476187 : && conv.m_fields.m_month > 0
154 952738 : && conv.m_fields.m_month < 13;
155 : }
156 :
157 :
158 : /** \brief Calculate the number of days in this date's month.
159 : *
160 : * This function uses this object's current month to determine how
161 : * many days are expected in that month.
162 : *
163 : * If the month field is invalid (not a number between 1 and 12 inclusive)
164 : * then the function returns -1 to indicate an error.
165 : *
166 : * The number of days is always 30 or 31 except for the month of February
167 : * in which case the function may return 28 or 29. For this reason, your
168 : * date must have the month and year you want to use to get a valid result
169 : * when calling this function.
170 : *
171 : * \note
172 : * This function is used to verify that the date month day is valid.
173 : *
174 : * \return The number of days in this date's current month.
175 : *
176 : * \sa isValid()
177 : */
178 476188 : int DOSDateTime::daysInMonth() const
179 : {
180 : dosdatetime_convert_t conv;
181 476188 : conv.m_dosdatetime = m_dosdatetime;
182 :
183 476188 : if(conv.m_fields.m_month == 0
184 476187 : || conv.m_fields.m_month > 12)
185 : {
186 1 : return -1;
187 : }
188 :
189 476187 : if(conv.m_fields.m_month == 2)
190 : {
191 : // Feb. depends on the year
192 : //
193 18995 : int year = conv.m_fields.m_year + 1980;
194 :
195 18995 : return ((year) % 400) == 0
196 37835 : ? 29
197 18840 : : (((year) % 100) == 0
198 37539 : ? 28
199 18699 : : (((year) % 4) == 0
200 18699 : ? 29
201 18995 : : 28));
202 : }
203 :
204 457192 : return g_days_in_month[conv.m_fields.m_month - 1];
205 : }
206 :
207 :
208 : /** \brief Get the second.
209 : *
210 : * This function returns the second this DOSDateTime object represents.
211 : *
212 : * The second is between 0 and 59 inclusive.
213 : *
214 : * \note
215 : * The DOSDateTime format only supports 5 bits for seconds. In other words,
216 : * the number can't go all the way from 0 to 59. Instead, the second
217 : * is saved without bit 0. In other words, only an even number of second
218 : * is saved. In other words, 0, 2, 4, 6, up to 58.
219 : *
220 : * \return The second this DOS Date & Time represents.
221 : */
222 142 : int DOSDateTime::getSecond() const
223 : {
224 : dosdatetime_convert_t conv;
225 142 : conv.m_dosdatetime = m_dosdatetime;
226 142 : return conv.m_fields.m_second * 2;
227 : }
228 :
229 :
230 : /** \brief Get the minute.
231 : *
232 : * This function returns the minute this DOSDateTime object represents.
233 : *
234 : * The minute is between 0 and 59 inclusive.
235 : *
236 : * \return The minute this DOS Date & Time represents.
237 : */
238 142 : int DOSDateTime::getMinute() const
239 : {
240 : dosdatetime_convert_t conv;
241 142 : conv.m_dosdatetime = m_dosdatetime;
242 142 : return conv.m_fields.m_minute;
243 : }
244 :
245 :
246 : /** \brief Get the hour.
247 : *
248 : * This function returns the hour this DOSDateTime object represents.
249 : *
250 : * The hour is between 0 and 23 inclusive.
251 : *
252 : * \return The hour this DOS Date & Time represents.
253 : */
254 106 : int DOSDateTime::getHour() const
255 : {
256 : dosdatetime_convert_t conv;
257 106 : conv.m_dosdatetime = m_dosdatetime;
258 106 : return conv.m_fields.m_hour;
259 : }
260 :
261 :
262 : /** \brief Get the day of the month.
263 : *
264 : * This function returns the day of month this DOSDateTime object represents.
265 : *
266 : * The day is between 1 and 31. To know whether a day is valid, use the
267 : * daysInMonth() function which returns the maximum number of days for a
268 : * given month.
269 : *
270 : * \return The day of the month this DOS Date & Time represents.
271 : */
272 115 : int DOSDateTime::getMDay() const
273 : {
274 : dosdatetime_convert_t conv;
275 115 : conv.m_dosdatetime = m_dosdatetime;
276 115 : return conv.m_fields.m_mday;
277 : }
278 :
279 :
280 : /** \brief Get the month.
281 : *
282 : * This function returns the month this DOSDateTime object represents.
283 : *
284 : * The month is between 1 and 12.
285 : *
286 : * \return The month this DOS Date & Time represents.
287 : */
288 95 : int DOSDateTime::getMonth() const
289 : {
290 : dosdatetime_convert_t conv;
291 95 : conv.m_dosdatetime = m_dosdatetime;
292 95 : return conv.m_fields.m_month;
293 : }
294 :
295 :
296 : /** \brief Get the year.
297 : *
298 : * This function returns the year this DOSDateTime object represents.
299 : *
300 : * The year is limited between 1980 and 2107.
301 : *
302 : * \return The year this DOS Date & Time represents.
303 : */
304 2274 : int DOSDateTime::getYear() const
305 : {
306 : dosdatetime_convert_t conv;
307 2274 : conv.m_dosdatetime = m_dosdatetime;
308 2274 : return conv.m_fields.m_year + 1980;
309 : }
310 :
311 :
312 : /** \brief Set the second.
313 : *
314 : * This function can be used to only change the second of a DOSDateTime
315 : * object.
316 : *
317 : * \note
318 : * The DOSDateTime format only supports 5 bits for seconds. In other words,
319 : * the number can't go all the way from 0 to 59. Instead, the second
320 : * is saved without bit 0. In other words, only an even number of second
321 : * is saved. In other words, 0, 2, 4, 6, up to 58.
322 : *
323 : * \attention
324 : * Leap seconds are not supported. Trying to pass 60 to this function
325 : * raises an InvalidException error.
326 : *
327 : * \exception InvalidException
328 : * The second is expected to be set to a number between 0 and 59 inclusive.
329 : * No exception is raised if an odd number is passed down. Bit 0 is simply
330 : * ignored.
331 : *
332 : * \param[in] second The new DOSDateTime number of seconds.
333 : */
334 144 : void DOSDateTime::setSecond(int second)
335 : {
336 144 : if(second < 0
337 124 : || second > 59)
338 : {
339 41 : throw InvalidException("Second is out of range for an MS-DOS Date & Time object. Range is [0, 59].");
340 : }
341 :
342 : dosdatetime_convert_t conv;
343 103 : conv.m_dosdatetime = m_dosdatetime;
344 103 : conv.m_fields.m_second = second / 2;
345 103 : m_dosdatetime = conv.m_dosdatetime;
346 103 : }
347 :
348 :
349 : /** \brief Set the minute.
350 : *
351 : * This function can be used to only change the minute of a DOSDateTime
352 : * object.
353 : *
354 : * \exception InvalidException
355 : * The minute is expected to be set to a number between 0 and 59 inclusive.
356 : *
357 : * \param[in] minute The new DOSDateTime number of minutes.
358 : */
359 144 : void DOSDateTime::setMinute(int minute)
360 : {
361 144 : if(minute < 0
362 124 : || minute > 59)
363 : {
364 41 : throw InvalidException("Minute is out of range for an MS-DOS Date & Time object. Range is [0, 59].");
365 : }
366 :
367 : dosdatetime_convert_t conv;
368 103 : conv.m_dosdatetime = m_dosdatetime;
369 103 : conv.m_fields.m_minute = minute;
370 103 : m_dosdatetime = conv.m_dosdatetime;
371 103 : }
372 :
373 :
374 : /** \brief Set the hour.
375 : *
376 : * This function can be used to only change the hour of a DOSDateTime
377 : * object.
378 : *
379 : * \exception InvalidException
380 : * The hour is expected to be set to a number between 0 and 23 inclusive.
381 : *
382 : * \param[in] hour The new DOSDateTime number of hours.
383 : */
384 108 : void DOSDateTime::setHour(int hour)
385 : {
386 108 : if(hour < 0
387 88 : || hour > 23)
388 : {
389 41 : throw InvalidException("Hour is out of range for an MS-DOS Date & Time object. Range is [0, 23].");
390 : }
391 :
392 : dosdatetime_convert_t conv;
393 67 : conv.m_dosdatetime = m_dosdatetime;
394 67 : conv.m_fields.m_hour = hour;
395 67 : m_dosdatetime = conv.m_dosdatetime;
396 67 : }
397 :
398 :
399 : /** \brief Set the day of the month.
400 : *
401 : * This function can be used to only change the day of the month of a
402 : * DOSDateTime object.
403 : *
404 : * \exception InvalidException
405 : * The day of the month is expected to be set to a number between 1 and 31
406 : * inclusive. An exception is raised if out of that range. Note that no
407 : * exception is raised if the day is invalid for a certain month because
408 : * at this point we can't be sure what the month will be. To verify once
409 : * you are done setting all the individual values, call isValid() to do
410 : * a final verification.
411 : *
412 : * \param[in] mday The new DOSDateTime day of the month.
413 : */
414 117 : void DOSDateTime::setMDay(int mday)
415 : {
416 117 : if(mday < 1
417 96 : || mday > 31)
418 : {
419 42 : throw InvalidException("Day of the month is out of range for an MS-DOS Date & Time object. Range is [1, 31].");
420 : }
421 :
422 : dosdatetime_convert_t conv;
423 75 : conv.m_dosdatetime = m_dosdatetime;
424 75 : conv.m_fields.m_mday = mday;
425 75 : m_dosdatetime = conv.m_dosdatetime;
426 75 : }
427 :
428 :
429 : /** \brief Set the month.
430 : *
431 : * This function can be used to only change the month of a DOSDateTime object.
432 : *
433 : * \exception InvalidException
434 : * The month is expected to be set to a number between 1 and 12 inclusive.
435 : *
436 : * \param[in] month The new DOSDateTime month.
437 : */
438 97 : void DOSDateTime::setMonth(int month)
439 : {
440 97 : if(month < 1
441 76 : || month > 12)
442 : {
443 42 : throw InvalidException("Month out of range for an MS-DOS Date & Time object. Range is [1, 12].");
444 : }
445 :
446 : dosdatetime_convert_t conv;
447 55 : conv.m_dosdatetime = m_dosdatetime;
448 55 : conv.m_fields.m_month = month;
449 55 : m_dosdatetime = conv.m_dosdatetime;
450 55 : }
451 :
452 :
453 : /** \brief Set the year.
454 : *
455 : * This function can be used to only change the year this DOSDateTime object
456 : * represents.
457 : *
458 : * \exception InvalidException
459 : * The year is limited between 1980 and 2107. This exception is raised if the
460 : * year to out of this range.
461 : *
462 : * \return The year this DOS Date & Time represents.
463 : */
464 2276 : void DOSDateTime::setYear(int year)
465 : {
466 2276 : if(year < 1980
467 1296 : || year > 2107)
468 : {
469 1073 : throw InvalidException("Year out of range for an MS-DOS Date & Time object. Range is [1980, 2107] (1).");
470 : }
471 :
472 : dosdatetime_convert_t conv;
473 1203 : conv.m_dosdatetime = m_dosdatetime;
474 1203 : conv.m_fields.m_year = year - 1980;
475 1203 : m_dosdatetime = conv.m_dosdatetime;
476 1203 : }
477 :
478 :
479 : /** \brief Retrieve the DOSDateTime value as is.
480 : *
481 : * This function returns the DOSDateTime value as is. It can then be used
482 : * in the zip file.
483 : *
484 : * \return The dosdatetime_t timestamp.
485 : */
486 791057 : DOSDateTime::dosdatetime_t DOSDateTime::getDOSDateTime() const
487 : {
488 791057 : return m_dosdatetime;
489 : }
490 :
491 :
492 : /** \brief Set the DOSDateTime value as is.
493 : *
494 : * This function sets this DOSDateTime object's timestamp to the specified
495 : * value. Any value is accepted by this function. To verify that the new
496 : * value is a valid date, use the isValid() function.
497 : *
498 : * \param[in] datetime The DOS Date & Time value.
499 : */
500 417983 : void DOSDateTime::setDOSDateTime(dosdatetime_t datetime)
501 : {
502 417983 : m_dosdatetime = datetime;
503 417983 : }
504 :
505 :
506 : /** \brief Set the DOSDateTime value from a Unix timestamp.
507 : *
508 : * This function accepts a Unix timestamp that gets converted to a
509 : * DOSDateTime object.
510 : *
511 : * A Unix timestamp is a time_t number representing seconds. 0 represents
512 : * the date Jan 1, 1970 at 00:00:00.
513 : *
514 : * The smallest Unix timestamp that can be represented in a DOSDateTime
515 : * object is 315532800 (0x12cea600) in UTC. Since the timestamp gets
516 : * converted to local time, though, the boundaries vary with the user's
517 : * timezone.
518 : *
519 : * The minimum date is represented as 0x00210000 in a DOSDateTime object.
520 : * This represents Jan 1, 1980 at 00:00:00, local time.
521 : *
522 : * The largest Unix timestamp that can be represented in a DOSDateTime
523 : * object is 4354819199 (0x10391447f) in UTC, since the timestamp gets
524 : * converted to local time, though, the boundaries vary with the user's
525 : * timezone.
526 : *
527 : * The maximum date is represented as 0xff9fbf7d in a DOSDateTime object.
528 : * Note that the Unix timestamp requires a 64 bit `time_t` representation
529 : * in order to reach the maximum DOSDateTime. With a 32 bit number,
530 : * the maximum is around 2037, about 70 years short. This maximum date
531 : * represents Dec 31, 2107 at 23:59:59, local time.
532 : *
533 : * \attention
534 : * The DOSDateTime object only holds even seconds. Odd seconds are lost
535 : * at the time this function gets called.
536 : *
537 : * \exception InvalidException
538 : * In 64 bits, a Unix timestamp can represent very large dates in both
539 : * directions (in the past and future.) If the Unix timestamp represents a
540 : * local date and time before Jan 1, 1980 at 00:00:00 or after
541 : * Dec 31, 2107 at 23:59:58, then this function raises this exception.
542 : * It is likely to raise an exception on Dec 31, 2107 at 23:59:59 because
543 : * we round the time to the next even second.
544 : *
545 : * \param[in] unix_timestamp The time and stamp in Unix format.
546 : */
547 810588 : void DOSDateTime::setUnixTimestamp(std::time_t unix_timestamp)
548 : {
549 : // round up to the next second
550 : //
551 810588 : unix_timestamp += 1;
552 810588 : unix_timestamp &= ~1;
553 :
554 : struct tm t;
555 : #ifdef ZIPIOS_WINDOWS
556 : localtime_s(&t, &unix_timestamp);
557 : #else
558 810588 : localtime_r(&unix_timestamp, &t);
559 : #endif
560 :
561 : //std::cout << "test with: " << unix_timestamp << " -- " << t.tm_year
562 : // << " (" << (t.tm_year < 1980 - 1900 ? 1 : 0)
563 : // << ", " << (t.tm_year > 2107 - 1900 ? 1 : 0)
564 : // << ")\n";
565 :
566 810588 : if(t.tm_year < 1980 - 1900
567 791205 : || t.tm_year > 2107 - 1900)
568 : {
569 19851 : throw InvalidException("Year out of range for an MS-DOS Date & Time object. Range is [1980, 2107] (2).");
570 : }
571 :
572 : dosdatetime_convert_t conv;
573 790737 : conv.m_fields.m_second = t.tm_sec / 2; // already rounded up to the next second, so just divide by 2 is enough here
574 790737 : conv.m_fields.m_minute = t.tm_min;
575 790737 : conv.m_fields.m_hour = t.tm_hour;
576 790737 : conv.m_fields.m_mday = t.tm_mday;
577 790737 : conv.m_fields.m_month = t.tm_mon + 1;
578 790737 : conv.m_fields.m_year = t.tm_year + 1900 - 1980;
579 :
580 790737 : m_dosdatetime = conv.m_dosdatetime;
581 790737 : }
582 :
583 :
584 : /** \brief Retrieve the DOSDateTime as a Unix timestamp.
585 : *
586 : * This function returns the DOSDateTime converted to a Unix timestamp.
587 : * On 64 bit platforms, all DOSDateTime can be converted to a Unix timestamp.
588 : * On a 32 bit platform, however, dates after 2037 can't be represented by
589 : * the Unix timestamp so this function throws (note that we did not check
590 : * the exact threshold because at this point I don't think it's too important.)
591 : *
592 : * \exception InvalidException
593 : * On 32 bit platform, dates that can't be represented in a Unix timestamp
594 : * throw this exception.
595 : *
596 : * \return The Unix timestamp representing the DOSDateTime object.
597 : *
598 : * \sa setUnixTimestamp()
599 : */
600 476123 : std::time_t DOSDateTime::getUnixTimestamp() const
601 : {
602 476123 : if(isValid())
603 : {
604 : dosdatetime_convert_t conv;
605 476103 : conv.m_dosdatetime = m_dosdatetime;
606 :
607 : struct tm t;
608 476103 : t.tm_sec = conv.m_fields.m_second * 2; // we lost the bottom bit, nothing we can do about it here
609 476103 : t.tm_min = conv.m_fields.m_minute;
610 476103 : t.tm_hour = conv.m_fields.m_hour;
611 476103 : t.tm_mday = conv.m_fields.m_mday;
612 476103 : t.tm_mon = conv.m_fields.m_month - 1;
613 476103 : t.tm_year = conv.m_fields.m_year + 1980 - 1900;
614 476103 : t.tm_wday = 0;
615 476103 : t.tm_yday = 0;
616 476103 : t.tm_isdst = -1;
617 :
618 : //std::cerr << "date to Unix timestamp: " << (t.tm_mon + 1) << " " << t.tm_mday << ", " << (t.tm_year + 1900)
619 : // << " " << t.tm_hour << ":" << t.tm_min << ":" << t.tm_sec << "\n";
620 :
621 : if(sizeof(std::time_t) == 4
622 : && t.tm_year >= 2038)
623 : {
624 : // the exact date is Jan 19, 2038 at 03:13:07 UTC
625 : // see https://en.wikipedia.org/wiki/Year_2038_problem
626 : //
627 : // we have no problem with 64 bits, max. year is about 292,000,000,000
628 : // although the tm_year is an int, so really we're limited to 2 billion
629 : // years, again just fine for a DOS Date is limited to 2107...
630 : //
631 : throw InvalidException("Year out of range for a 32 bit Unix Timestamp object. Range is (1901, 2038).");
632 : }
633 :
634 : // the zip file format expects dates in local time, not UTC
635 : // so I use mktime() directly
636 : //
637 476103 : return mktime(&t);
638 :
639 : // // mktime() makes use of the timezone, here is some code that
640 : // // replaces mktime() with a UTC date conversion
641 : // //
642 : // time_t const year = t.tm_year + 1900;
643 : // time_t timestamp = (year - 1970LL) * 31536000LL
644 : // + ((year - 1969LL) / 4LL) * 86400LL
645 : // - ((year - 1901LL) / 100LL) * 86400LL
646 : // + ((year - 1601LL) / 400LL) * 86400LL
647 : // + (t.tm_mday + g_ydays[t.tm_mon] - 1) * 86400LL
648 : // + t.tm_hour * 3600LL
649 : // + t.tm_min * 60LL
650 : // + t.tm_sec * 1LL;
651 : // if(t.tm_mon >= 2)
652 : // {
653 : // // add seconds in February
654 : // //
655 : // timestamp += (year % 400 == 0
656 : // ? 29 // for year 2000
657 : // : (year % 100 == 0
658 : // ? 28 // for year 2100
659 : // : (year % 4 == 0
660 : // ? 29
661 : // : 28))) * 86400LL;
662 : // }
663 : //
664 : // return timestamp;
665 : }
666 :
667 20 : return 0;
668 : }
669 :
670 :
671 :
672 :
673 : } // zipios namespace
674 :
675 : // Local Variables:
676 : // mode: cpp
677 : // indent-tabs-mode: nil
678 : // c-basic-offset: 4
679 : // tab-width: 4
680 : // End:
681 :
682 : // vim: ts=4 sw=4 et
|