CFAbsoluteTime CFGregorianDateGetAbsoluteTime(CFGregorianDate gdate, CFTimeZoneRef tz) { CFAbsoluteTime at; CFTimeInterval offset0, offset1; at = 86400.0 * __CFAbsoluteFromYMD(gdate.year - 2001, gdate.month, gdate.day); at += 3600.0 * gdate.hour + 60.0 * gdate.minute + gdate.second; if (tz) { offset0 = CFTimeZoneGetSecondsFromGMT(tz, at); offset1 = CFTimeZoneGetSecondsFromGMT(tz, at - offset0); at -= offset1; } return at; }
/** * MacDateTime::LocalTZA * * Determines the Local Time Zone Adjustment, in seconds from GMT */ double MacDateTime::LocalTZA(double time) { CFTimeZoneRef tz = CFTimeZoneCopySystem(); if (tz) { CFAbsoluteTime at = ECMADateToCFAbsoluteTime(time); // pass now as the reference. // This will include any daylight savings offsets in the result. CFTimeInterval result = CFTimeZoneGetSecondsFromGMT(tz, at); CFRelease(tz); result *= kMsecPerSecond; // Remove the effects of daylight saving time return ( result -= MacDateTime::DaylightSavingTA(time) ); } MachineLocation location; ReadMachineLocation(&location); // Extract the GMT delta long gmtDelta = location.u.gmtDelta & 0xFFFFFF; if (gmtDelta & 0x800000) { gmtDelta |= 0xFF000000; } // Remove the effects of daylight saving time if (location.u.dlsDelta < 0) { gmtDelta -= 3600; } return (double)gmtDelta * kMsecPerSecond; }
/* "the first week of a year is the one which includes the first Thursday" (ISO 8601) */ SInt32 CFAbsoluteTimeGetWeekOfYear(CFAbsoluteTime at, CFTimeZoneRef tz) { int64_t absolute, year; int8_t month, day; CFAbsoluteTime fixedat; fixedat = at + (tz ? CFTimeZoneGetSecondsFromGMT(tz, at) : 0.0); absolute = (int64_t)floor(fixedat / 86400.0); __CFYMDFromAbsolute(absolute, &year, &month, &day); double absolute0101 = __CFAbsoluteFromYMD(year, 1, 1); int64_t dow0101 = __CFDoubleModToInt(absolute0101, 7) + 1; /* First three and last three days of a year can end up in a week of a different year */ if (1 == month && day < 4) { if ((day < 4 && 5 == dow0101) || (day < 3 && 6 == dow0101) || (day < 2 && 7 == dow0101)) { return 53; } } if (12 == month && 28 < day) { double absolute20101 = __CFAbsoluteFromYMD(year + 1, 1, 1); int64_t dow20101 = __CFDoubleModToInt(absolute20101, 7) + 1; if ((28 < day && 4 == dow20101) || (29 < day && 3 == dow20101) || (30 < day && 2 == dow20101)) { return 1; } } /* Days into year, plus a week-shifting correction, divided by 7. First week is 1. */ return (__CFDaysBeforeMonth(month, year) + day + (dow0101 - 11) % 7 + 2) / 7 + 1; }
void MacLongDateTimeToTimeString(const sint64 &inMacDate, uint32 inLength, void *outData) { // @@@ this code is close, but on the fringe case of a daylight savings time it will be off for a little while CFAbsoluteTime absTime = inMacDate - kCFAbsoluteTimeIntervalSince1904; // Remove local timezone component from absTime CFTimeZoneRef timeZone = CFTimeZoneCopyDefault(); absTime -= CFTimeZoneGetSecondsFromGMT(timeZone, absTime); CFRelease(timeZone); timeZone = CFTimeZoneCreateWithTimeIntervalFromGMT(NULL, 0); CFGregorianDate date = CFAbsoluteTimeGetGregorianDate(absTime, timeZone); CFRelease(timeZone); if (inLength == 16) { sprintf((char *)(outData), "%04d%02d%02d%02d%02d%02dZ", int(date.year % 10000), date.month, date.day, date.hour, date.minute, int(date.second)); } else if (inLength == 14) { /* UTC - 2 year digits - code which parses this assumes that * (2-digit) years between 0 and 49 are in century 21 */ sprintf((char *)(outData), "%02d%02d%02d%02d%02d%02dZ", int(date.year % 100), date.month, date.day, date.hour, date.minute, int(date.second)); } else MacOSError::throwMe(paramErr); }
SInt32 CFAbsoluteTimeGetDayOfWeek(CFAbsoluteTime at, CFTimeZoneRef tz) { int64_t absolute; CFAbsoluteTime fixedat; fixedat = at + (tz ? CFTimeZoneGetSecondsFromGMT(tz, at) : 0.0); absolute = (int64_t)floor(fixedat / 86400.0); return (absolute < 0) ? ((absolute + 1) % 7 + 7) : (absolute % 7 + 1); /* Monday = 1, etc. */ }
void GetCurrentMacLongDateTime(sint64 &outMacDate) { CFTimeZoneRef timeZone = CFTimeZoneCopyDefault(); CFAbsoluteTime absTime = CFAbsoluteTimeGetCurrent(); absTime += CFTimeZoneGetSecondsFromGMT(timeZone, absTime); CFRelease(timeZone); outMacDate = sint64(double(absTime + kCFAbsoluteTimeIntervalSince1904)); }
SInt32 CFAbsoluteTimeGetDayOfYear(CFAbsoluteTime at, CFTimeZoneRef tz) { CFAbsoluteTime fixedat; int64_t absolute, year; int8_t month, day; fixedat = at + (tz ? CFTimeZoneGetSecondsFromGMT(tz, at) : 0.0); absolute = (int64_t)floor(fixedat / 86400.0); __CFYMDFromAbsolute(absolute, &year, &month, &day); return __CFDaysBeforeMonth(month, year) + day; }
CFGregorianDate CFAbsoluteTimeGetGregorianDate(CFAbsoluteTime at, CFTimeZoneRef tz) { CFGregorianDate gdate; int64_t absolute, year; int8_t month, day; CFAbsoluteTime fixedat; fixedat = at + (tz ? CFTimeZoneGetSecondsFromGMT(tz, at) : 0.0); absolute = (int64_t)floor(fixedat / 86400.0); __CFYMDFromAbsolute(absolute, &year, &month, &day); if (INT32_MAX - 2001 < year) { year = INT32_MAX - 2001; } gdate.year = (SInt32)(year + 2001); gdate.month = month; gdate.day = day; gdate.hour = __CFDoubleModToInt(floor(fixedat / 3600.0), 24); gdate.minute = __CFDoubleModToInt(floor(fixedat / 60.0), 60); gdate.second = __CFDoubleMod(fixedat, 60); if (0.0 == gdate.second) { gdate.second = 0.0; // stomp out possible -0.0 } return gdate; }
dng_time_zone LocalTimeZone (const dng_date_time &dt) { dng_time_zone result; if (dt.IsValid ()) { #if qMacOS CFTimeZoneRef zoneRef = CFTimeZoneCopyDefault (); if (zoneRef) { CFGregorianDate gregDate; gregDate.year = dt.fYear; gregDate.month = dt.fMonth; gregDate.day = dt.fDay; gregDate.hour = dt.fHour; gregDate.minute = dt.fMinute; gregDate.second = dt.fSecond; CFAbsoluteTime absTime = CFGregorianDateGetAbsoluteTime (gregDate, zoneRef); CFTimeInterval secondsDelta = CFTimeZoneGetSecondsFromGMT (zoneRef, absTime); CFRelease (zoneRef); result.SetOffsetSeconds (secondsDelta); if (result.IsValid ()) { return result; } } #endif #if qWinOS if (GetTimeZoneInformation != NULL && SystemTimeToTzSpecificLocalTime != NULL && SystemTimeToFileTime != NULL) { TIME_ZONE_INFORMATION tzInfo; DWORD x = GetTimeZoneInformation (&tzInfo); SYSTEMTIME localST; memset (&localST, 0, sizeof (localST)); localST.wYear = (WORD) dt.fYear; localST.wMonth = (WORD) dt.fMonth; localST.wDay = (WORD) dt.fDay; localST.wHour = (WORD) dt.fHour; localST.wMinute = (WORD) dt.fMinute; localST.wSecond = (WORD) dt.fSecond; SYSTEMTIME utcST; if (TzSpecificLocalTimeToSystemTime (&tzInfo, &localST, &utcST)) { FILETIME localFT; FILETIME utcFT; (void) SystemTimeToFileTime (&localST, &localFT); (void) SystemTimeToFileTime (&utcST , &utcFT ); uint64 time1 = (((uint64) localFT.dwHighDateTime) << 32) + localFT.dwLowDateTime; uint64 time2 = (((uint64) utcFT .dwHighDateTime) << 32) + utcFT .dwLowDateTime; // FILETIMEs are in units to 100 ns. Convert to seconds. int64 time1Sec = time1 / 10000000; int64 time2Sec = time2 / 10000000; int32 delta = (int32) (time1Sec - time2Sec); result.SetOffsetSeconds (delta); if (result.IsValid ()) { return result; } } } #endif } // Figure out local time zone. dng_date_time_info current_info; CurrentDateTimeAndZone (current_info); result = current_info.TimeZone (); return result; }
/* * Parse a GeneralizedTime string into a CFAbsoluteTime. Returns NULL on parse error. * Fractional parts of a second are discarded. */ CFAbsoluteTime genTimeToCFAbsTime( const CSSM_DATA *strData) { if((strData == NULL) || (strData->Data == NULL) || (strData->Length == 0)) { return NULL_TIME; } uint8 *timeStr = strData->Data; size_t timeStrLen = strData->Length; /* tolerate NULL terminated or not */ if(timeStr[timeStrLen - 1] == '\0') { timeStrLen--; } /* start with a fresh editable copy */ uint8 *str = (uint8 *)malloc(timeStrLen); uint32 strLen = 0; /* * If there is a decimal point, strip it and all trailing digits off */ const uint8 *inCp = timeStr; uint8 *outCp = str; int foundDecimal = 0; int minutesOffset = 0; int hoursOffset = 0; bool minusOffset = false; bool isGMT = false; size_t toGo = timeStrLen; do { if(*inCp == '.') { if(foundDecimal) { /* only legal once */ { free(str); return NULL_TIME; } } foundDecimal++; /* skip the decimal point... */ inCp++; toGo--; if(toGo == 0) { /* all done */ break; } /* then all subsequent contiguous digits */ while(isdigit(*inCp) && (toGo != 0)) { inCp++; toGo--; } } /* decimal point processing */ else if((*inCp == '+') || (*inCp == '-')) { /* Time zone offset - handle 2 or 4 chars */ if((toGo != 2) & (toGo != 4)) { free(str); return NULL_TIME; } if(*inCp == '-') { minusOffset = true; } inCp++; hoursOffset = (10 * (inCp[0] - '0')) + (inCp[1] - '0'); toGo -= 2; if(toGo) { minutesOffset = (10 * (inCp[0] - '0')) + (inCp[1] - '0'); toGo -= 2; } } else { *outCp++ = *inCp++; strLen++; toGo--; } } while(toGo != 0); if(str[strLen - 1] == 'Z') { isGMT = true; strLen--; } CFAbsoluteTime absTime; absTime = parseGenTime(str, strLen); free(str); if(absTime == NULL_TIME) { return NULL_TIME; } /* post processing needed? */ if(isGMT) { /* Nope, string was in GMT */ return absTime; } if((minutesOffset != 0) || (hoursOffset != 0)) { /* string contained explicit offset from GMT */ if(minusOffset) { absTime -= (minutesOffset * 60); absTime -= (hoursOffset * 3600); } else { absTime += (minutesOffset * 60); absTime += (hoursOffset * 3600); } } else { /* implciit offset = local */ CFTimeInterval tzDelta; CFTimeZoneRef localZone = CFTimeZoneCopySystem(); tzDelta = CFTimeZoneGetSecondsFromGMT (localZone, CFAbsoluteTimeGetCurrent()); CFRelease(localZone); absTime += tzDelta; } return absTime; }
/* * Given a CSSM_DATA containing either a UTC-style or "generalized time" * time string, convert to 32-bit Mac time in seconds. * Returns nonzero on error. */ void TimeStringToMacLongDateTime (const CSSM_DATA &inUTCTime, sint64 &outMacDate) { char szTemp[5]; unsigned len; int isUtc; sint32 x; sint32 i; char *cp; CFGregorianDate date; ::memset( &date, 0, sizeof(date) ); if ((inUTCTime.Data == NULL) || (inUTCTime.Length == 0)) { MacOSError::throwMe(paramErr); } /* tolerate NULL terminated or not */ len = inUTCTime.Length; if (inUTCTime.Data[len - 1] == '\0') len--; switch(len) { case UTC_TIME_STRLEN: // 2-digit year, not Y2K compliant isUtc = 1; break; case GENERALIZED_TIME_STRLEN: // 4-digit year isUtc = 0; break; default: // unknown format MacOSError::throwMe(paramErr); } cp = (char *)inUTCTime.Data; /* check that all characters except last are digits */ for(i=0; i<(sint32)(len - 1); i++) { if ( !(isdigit(cp[i])) ) { MacOSError::throwMe(paramErr); } } /* check last character is a 'Z' */ if(cp[len - 1] != 'Z' ) { MacOSError::throwMe(paramErr); } /* YEAR */ szTemp[0] = *cp++; szTemp[1] = *cp++; if(!isUtc) { /* two more digits */ szTemp[2] = *cp++; szTemp[3] = *cp++; szTemp[4] = '\0'; } else { szTemp[2] = '\0'; } x = atoi( szTemp ); if(isUtc) { /* * 2-digit year. * 0 <= year <= 50 : assume century 21 * 50 < year < 70 : illegal per PKIX * 70 < year <= 99 : assume century 20 */ if(x <= 50) { x += 100; } else if(x < 70) { MacOSError::throwMe(paramErr); } /* else century 20, OK */ /* bug fix... we need to end up with a 4-digit year! */ x += 1900; } /* by definition - tm_year is year - 1900 */ //tmp->tm_year = x - 1900; date.year = x; /* MONTH */ szTemp[0] = *cp++; szTemp[1] = *cp++; szTemp[2] = '\0'; x = atoi( szTemp ); /* in the string, months are from 1 to 12 */ if((x > 12) || (x <= 0)) { MacOSError::throwMe(paramErr); } /* in a tm, 0 to 11 */ //tmp->tm_mon = x - 1; date.month = x; /* DAY */ szTemp[0] = *cp++; szTemp[1] = *cp++; szTemp[2] = '\0'; x = atoi( szTemp ); /* 1..31 in both formats */ if((x > 31) || (x <= 0)) { MacOSError::throwMe(paramErr); } //tmp->tm_mday = x; date.day = x; /* HOUR */ szTemp[0] = *cp++; szTemp[1] = *cp++; szTemp[2] = '\0'; x = atoi( szTemp ); if((x > 23) || (x < 0)) { MacOSError::throwMe(paramErr); } //tmp->tm_hour = x; date.hour = x; /* MINUTE */ szTemp[0] = *cp++; szTemp[1] = *cp++; szTemp[2] = '\0'; x = atoi( szTemp ); if((x > 59) || (x < 0)) { MacOSError::throwMe(paramErr); } //tmp->tm_min = x; date.minute = x; /* SECOND */ szTemp[0] = *cp++; szTemp[1] = *cp++; szTemp[2] = '\0'; x = atoi( szTemp ); if((x > 59) || (x < 0)) { MacOSError::throwMe(paramErr); } //tmp->tm_sec = x; date.second = x; CFTimeZoneRef timeZone = CFTimeZoneCreateWithTimeIntervalFromGMT(NULL, 0); CFAbsoluteTime absTime = CFGregorianDateGetAbsoluteTime(date, timeZone); CFRelease(timeZone); // Adjust abstime to local timezone timeZone = CFTimeZoneCopyDefault(); absTime += CFTimeZoneGetSecondsFromGMT(timeZone, absTime); CFRelease(timeZone); outMacDate = sint64(double(absTime + kCFAbsoluteTimeIntervalSince1904)); }