zipios 2.2.0
Zipios -- a small C++ library that provides easy access to .zip files.
dosdatetime.cpp
Go to the documentation of this file.
1/*
2 Zipios -- a small C++ library that provides easy access to .zip files.
3
4 Copyright (C) 2019 Made to Order Software Corporation
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
36
38
39
40namespace zipios
41{
42
43
46
47
48
49
60{
62 struct fields
63 {
64 DOSDateTime::dosdatetime_t m_second : 5; // WARNING: the precision is every 2 seconds (0, 2, 4, etc.)
71};
72
73
74
75namespace
76{
77
83int const g_days_in_month[12] = {
84 /* Jan */ 31,
85 /* Feb */ 0, // special handling
86 /* Mar */ 31,
87 /* Apr */ 30,
88 /* May */ 31,
89 /* Jun */ 30,
90 /* Jul */ 31,
91 /* Aug */ 31,
92 /* Sep */ 30,
93 /* Oct */ 31,
94 /* Nov */ 30,
95 /* Dec */ 31
96};
97
98
99int const g_ydays[12] = {
100 /* Jan */ 0,
101 /* Feb */ 31,
102 /* Mar */ 31 + 0, // special handling
103 /* Apr */ 31 + 0 + 31,
104 /* May */ 31 + 0 + 31 + 30,
105 /* Jun */ 31 + 0 + 31 + 30 + 31,
106 /* Jul */ 31 + 0 + 31 + 30 + 31 + 30,
107 /* Aug */ 31 + 0 + 31 + 30 + 31 + 30 + 31,
108 /* Sep */ 31 + 0 + 31 + 30 + 31 + 30 + 31 + 31,
109 /* Oct */ 31 + 0 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
110 /* Nov */ 31 + 0 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
111 /* Dec */ 31 + 0 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30
112};
113
114
115}
116
117
118
140{
143 return conv.m_fields.m_second < 30 // remember we only keep `sec / 2` in a DOS time field
144 && conv.m_fields.m_minute < 60
145 && conv.m_fields.m_hour < 24
146 && conv.m_fields.m_mday > 0
147 && conv.m_fields.m_mday <= daysInMonth()
148 && conv.m_fields.m_month > 0
149 && conv.m_fields.m_month < 13;
150}
151
152
174{
177
178 if(conv.m_fields.m_month == 0
179 || conv.m_fields.m_month > 12)
180 {
181 return -1;
182 }
183
184 if(conv.m_fields.m_month == 2)
185 {
186 // Feb. depends on the year
187 //
188 int year = conv.m_fields.m_year + 1980;
189
190 return ((year) % 400) == 0
191 ? 29
192 : (((year) % 100) == 0
193 ? 28
194 : (((year) % 4) == 0
195 ? 29
196 : 28));
197 }
198
199 return g_days_in_month[conv.m_fields.m_month - 1];
200}
201
202
218{
221 return conv.m_fields.m_second * 2;
222}
223
224
234{
237 return conv.m_fields.m_minute;
238}
239
240
250{
253 return conv.m_fields.m_hour;
254}
255
256
268{
271 return conv.m_fields.m_mday;
272}
273
274
284{
287 return conv.m_fields.m_month;
288}
289
290
300{
303 return conv.m_fields.m_year + 1980;
304}
305
306
330{
331 if(second < 0
332 || second > 59)
333 {
334 throw InvalidException("Second is out of range for an MS-DOS Date & Time object. Range is [0, 59].");
335 }
336
339 conv.m_fields.m_second = second / 2;
341}
342
343
355{
356 if(minute < 0
357 || minute > 59)
358 {
359 throw InvalidException("Minute is out of range for an MS-DOS Date & Time object. Range is [0, 59].");
360 }
361
364 conv.m_fields.m_minute = minute;
366}
367
368
380{
381 if(hour < 0
382 || hour > 23)
383 {
384 throw InvalidException("Hour is out of range for an MS-DOS Date & Time object. Range is [0, 23].");
385 }
386
389 conv.m_fields.m_hour = hour;
391}
392
393
410{
411 if(mday < 1
412 || mday > 31)
413 {
414 throw InvalidException("Day of the month is out of range for an MS-DOS Date & Time object. Range is [1, 31].");
415 }
416
419 conv.m_fields.m_mday = mday;
421}
422
423
434{
435 if(month < 1
436 || month > 12)
437 {
438 throw InvalidException("Month out of range for an MS-DOS Date & Time object. Range is [1, 12].");
439 }
440
443 conv.m_fields.m_month = month;
445}
446
447
460{
461 if(year < 1980
462 || year > 2107)
463 {
464 throw InvalidException("Year out of range for an MS-DOS Date & Time object. Range is [1980, 2107].");
465 }
466
469 conv.m_fields.m_year = year - 1980;
471}
472
473
482{
483 return m_dosdatetime;
484}
485
486
496{
497 m_dosdatetime = datetime;
498}
499
500
542void DOSDateTime::setUnixTimestamp(std::time_t unix_timestamp)
543{
544 // round up to the next second
545 //
546 unix_timestamp += 1;
547 unix_timestamp &= -2;
548
549 struct tm t;
550 localtime_r(&unix_timestamp, &t);
551
552//std::cerr << "test with: " << unix_timestamp << " -- " << t.tm_year
553// << " (" << (t.tm_year < 1980 - 1900 ? 1 : 0)
554// << ", " << (t.tm_year > 2107 - 1900 ? 1 : 0)
555// << ")\n";
556
557 if(t.tm_year < 1980 - 1900
558 || t.tm_year > 2107 - 1900)
559 {
560 throw InvalidException("Year out of range for an MS-DOS Date & Time object. Range is [1980, 2107].");
561 }
562
564 conv.m_fields.m_second = t.tm_sec / 2; // already rounded up to the next second, so just divide by 2 is enough here
565 conv.m_fields.m_minute = t.tm_min;
566 conv.m_fields.m_hour = t.tm_hour;
567 conv.m_fields.m_mday = t.tm_mday;
568 conv.m_fields.m_month = t.tm_mon + 1;
569 conv.m_fields.m_year = t.tm_year + 1900 - 1980;
570
572}
573
574
592{
593 if(isValid())
594 {
597
598 struct tm t;
599 t.tm_sec = conv.m_fields.m_second * 2; // we lost the bottom bit, nothing we can do about it here
600 t.tm_min = conv.m_fields.m_minute;
601 t.tm_hour = conv.m_fields.m_hour;
602 t.tm_mday = conv.m_fields.m_mday;
603 t.tm_mon = conv.m_fields.m_month - 1;
604 t.tm_year = conv.m_fields.m_year + 1980 - 1900;
605 t.tm_wday = 0;
606 t.tm_yday = 0;
607 t.tm_isdst = -1;
608
609//std::cerr << "date to Unix timestamp: " << (t.tm_mon + 1) << " " << t.tm_mday << ", " << (t.tm_year + 1900)
610// << " " << t.tm_hour << ":" << t.tm_min << ":" << t.tm_sec << "\n";
611
612 if(sizeof(std::time_t) == 4
613 && t.tm_year >= 2038)
614 {
615 // the exact date is Jan 19, 2038 at 03:13:07 UTC
616 // see https://en.wikipedia.org/wiki/Year_2038_problem
617 //
618 // we have no problem with 64 bits, max. year is about 292,000,000,000
619 // although the tm_year is an int, so really we're limited to 2 billion
620 // years, again just fine for a DOS Date is limited to 2107...
621 //
622 throw InvalidException("Year out of range for a 32 bit Unix Timestamp object. Range is (1901, 2038).");
623 }
624
625 return mktime(&t);
626
627// // mktime() makes use of the timezone, here is some code that
628// // replaces mktime() with a UTC date conversion
629// //
630// time_t const year = t.tm_year + 1900;
631// time_t timestamp = (year - 1970LL) * 31536000LL
632// + ((year - 1969LL) / 4LL) * 86400LL
633// - ((year - 1901LL) / 100LL) * 86400LL
634// + ((year - 1601LL) / 400LL) * 86400LL
635// + (t.tm_mday + g_ydays[t.tm_mon] - 1) * 86400LL
636// + t.tm_hour * 3600LL
637// + t.tm_min * 60LL
638// + t.tm_sec * 1LL;
639// if(t.tm_mon >= 2)
640// {
641// // add seconds in February
642// //
643// timestamp += (year % 400 == 0
644// ? 29 // for year 2000
645// : (year % 100 == 0
646// ? 28 // for year 2100
647// : (year % 4 == 0
648// ? 29
649// : 28))) * 86400LL;
650// }
651//
652// return timestamp;
653 }
654
655 return 0;
656}
657
658
659
660
661} // zipios namespace
662
663// Local Variables:
664// mode: cpp
665// indent-tabs-mode: nil
666// c-basic-offset: 4
667// tab-width: 4
668// End:
669
670// vim: ts=4 sw=4 et
dosdatetime_t m_dosdatetime
Definition: dosdatetime.hpp:72
dosdatetime_t getDOSDateTime() const
Retrieve the DOSDateTime value as is.
int getMinute() const
Get the minute.
std::time_t getUnixTimestamp() const
Retrieve the DOSDateTime as a Unix timestamp.
bool isValid() const
Check whether this DOS Date & Date is valid.
int getSecond() const
Get the second.
int daysInMonth() const
Calculate the number of days in this date's month.
void setDOSDateTime(dosdatetime_t datetime)
Set the DOSDateTime value as is.
int getMonth() const
Get the month.
static dosdatetime_t const g_max_dosdatetime
Definition: dosdatetime.hpp:50
static dosdatetime_t const g_min_dosdatetime
Definition: dosdatetime.hpp:49
void setSecond(int second)
Set the second.
void setYear(int year)
Set the year.
void setHour(int hour)
Set the hour.
void setMonth(int month)
Set the month.
void setUnixTimestamp(std::time_t unix_timestamp)
Set the DOSDateTime value from a Unix timestamp.
int getMDay() const
Get the day of the month.
int getYear() const
Get the year.
void setMDay(int mday)
Set the day of the month.
void setMinute(int minute)
Set the minute.
int getHour() const
Get the hour.
An InvalidException is used when invalid data is provided.
Define a type to manage date and time in MS-DOS format.
int const g_days_in_month[12]
Number of days in a month.
Definition: dosdatetime.cpp:83
The zipios namespace includes the Zipios library definitions.
Definition: backbuffer.cpp:36
DOSDateTime::dosdatetime_t m_year
Definition: dosdatetime.cpp:69
DOSDateTime::dosdatetime_t m_second
Definition: dosdatetime.cpp:64
DOSDateTime::dosdatetime_t m_month
Definition: dosdatetime.cpp:68
DOSDateTime::dosdatetime_t m_minute
Definition: dosdatetime.cpp:65
DOSDateTime::dosdatetime_t m_mday
Definition: dosdatetime.cpp:67
DOSDateTime::dosdatetime_t m_hour
Definition: dosdatetime.cpp:66
Union used to convert the uint32_t to fields and vice versa.
Definition: dosdatetime.cpp:60
DOSDateTime::dosdatetime_t m_dosdatetime
Definition: dosdatetime.cpp:61
struct zipios::dosdatetime_convert_t::fields m_fields
Various exceptions used throughout the Zipios library, all based on zipios::Exception.