Index: lib/sdk/crt/time/strftime.c =================================================================== --- lib/sdk/crt/time/strftime.c (revision 57579) +++ lib/sdk/crt/time/strftime.c (working copy) @@ -8,6 +8,13 @@ #include #include +typedef struct _ISO8601_TIME +{ + int week; + int year; + int short_year; +} ISO8601_TIME, *PISO8601_TIME; + size_t _tcsftime(_TCHAR *strDest, size_t maxsize, @@ -17,3 +24,123 @@ return 0; } +/* first_wday + * Gives you the yday for the first occurence of @wday in the year described + * by time.tm_wday and time.tm_yday. + * Does not validate the 'realness' of the year. + * Necessary for calculating %g, %G, %V and %U. + */ +static +int +first_wday(struct tm time, int wday) +{ + TCHAR circ_week[] = _T("\x0A\x01\x02\x03\x04\x05\x06\x0A\x01\x02\x03\x04\x05\x06"); + int days_till; + int f_mon; + TCHAR* mon_ptr; + + if (time.tm_wday < 0 || time.tm_wday > 6 || time.tm_yday < 0 || time.tm_yday > 365 || wday < 0 || wday > 6) + return -1; + + if (0 == wday) + wday = 0x0A; + + // If true, time.tm_wday first day is in the first week of the year + // If false, in second week + if (time.tm_yday % 7 <= time.tm_wday) + mon_ptr = _tcschr(&circ_week[time.tm_wday], wday); + else + mon_ptr = _tcschr(circ_week, wday); + + if (NULL == mon_ptr) + return -1; + + days_till = mon_ptr - &circ_week[time.tm_wday]; + f_mon = circ_week[time.tm_yday % 7 + days_till] % 0x0A; + + return f_mon; +} + +static +int +year_length(int year) +{ + int y; + if (year >= 0) { + y = year + 1900; + if (!(y % 400)) + return 366; + else if (!(y % 100)) + return 365; + else if (!(y % 4)) + return 366; + else + return 365; + } + return -1; +} + +static +int +tm_to_iso8601(struct tm time, ISO8601_TIME *isotime) +{ + int yl; + int prev_yl; + int first_monday; + int first_friday; + int delta; + + yl = year_length(time.tm_year); + first_monday = first_wday(time, 1); + if (time.tm_yday >= 0 && time.tm_yday <= 365 && + time.tm_wday >= 0 && time.tm_wday <= 6 && + yl >= 0 && first_monday >= 0) + { + if (time.tm_yday < first_monday && first_monday <= 3) + { + /* Last week of previous year + * Determine if the previous year had 53 weeks + * 1) Regular years start and end on the same weekday + * 2) Leap years end on the weekday after the first day + * 3) A year must have a Thursday in the first and last week in order to have 53 weeks + */ + first_friday = first_wday(time, 5); + if (first_friday < 0) + return -1; + + prev_yl = year_length(time.tm_year - 1); + if (prev_yl < 0) + return -1; + + if ((365 == prev_yl && first_friday == 0) || (366 == prev_yl && (first_friday == 0 || first_friday == 6))) + isotime->week = 53; + else + isotime->week = 52; + + isotime->year = time.tm_year - 1 + 1900; + isotime->short_year = isotime->year % 100; + } + else if ((time.tm_wday >= 1 && time.tm_wday <= 3) && + (time.tm_yday >= (yl - 3) + (time.tm_wday - 1))) + { + /* First week of next year + * ----- Cases ----- + * Leap Year => {Monday >= 363, Tuesday >= 364, Wednesday >= 365} + * NonLeap Year => {Monday >= 362, Tuesday >= 363, Wendesday >= 364} + */ + isotime->week = 1; + isotime->year = time.tm_year + 1 + 1900; + isotime->short_year = isotime->year % 100; + } + else + { + // The first Monday of the year is in the second week + delta = time.tm_yday - first_wday(time, 1); + isotime->week = (delta < 0 ? -1 : delta/7) + (first_monday >= 4 ? 1 : 0) + 1; + isotime->year = time.tm_year + 1900; + isotime->short_year = isotime->year % 100; + } + return 1; + } + return -1; +}