You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
978 lines
17 KiB
978 lines
17 KiB
/*****************************************************************************/
|
|
// Copyright 2006-2008 Adobe Systems Incorporated
|
|
// All Rights Reserved.
|
|
//
|
|
// NOTICE: Adobe permits you to use, modify, and distribute this file in
|
|
// accordance with the terms of the Adobe license agreement accompanying it.
|
|
/*****************************************************************************/
|
|
|
|
/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_date_time.cpp#2 $ */
|
|
/* $DateTime: 2012/06/01 07:28:57 $ */
|
|
/* $Change: 832715 $ */
|
|
/* $Author: tknoll $ */
|
|
|
|
/*****************************************************************************/
|
|
|
|
#include "dng_date_time.h"
|
|
|
|
#include "dng_exceptions.h"
|
|
#include "dng_mutex.h"
|
|
#include "dng_stream.h"
|
|
#include "dng_string.h"
|
|
#include "dng_utils.h"
|
|
|
|
#include <time.h>
|
|
|
|
#if qMacOS
|
|
#include <TargetConditionals.h>
|
|
#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
|
|
#include <MobileCoreServices/MobileCoreServices.h>
|
|
#else
|
|
#include <CoreServices/CoreServices.h>
|
|
#endif // TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
|
|
#endif // qMacOS
|
|
|
|
#if qWinOS
|
|
#include <windows.h>
|
|
#endif
|
|
|
|
/******************************************************************************/
|
|
|
|
// MWG says don't use fake time zones in XMP, but there is some
|
|
// old software that requires them to work correctly.
|
|
|
|
bool gDNGUseFakeTimeZonesInXMP = false;
|
|
|
|
/******************************************************************************/
|
|
|
|
dng_date_time::dng_date_time ()
|
|
|
|
: fYear (0)
|
|
, fMonth (0)
|
|
, fDay (0)
|
|
, fHour (0)
|
|
, fMinute (0)
|
|
, fSecond (0)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
/******************************************************************************/
|
|
|
|
dng_date_time::dng_date_time (uint32 year,
|
|
uint32 month,
|
|
uint32 day,
|
|
uint32 hour,
|
|
uint32 minute,
|
|
uint32 second)
|
|
|
|
: fYear (year)
|
|
, fMonth (month)
|
|
, fDay (day)
|
|
, fHour (hour)
|
|
, fMinute (minute)
|
|
, fSecond (second)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
/******************************************************************************/
|
|
|
|
bool dng_date_time::IsValid () const
|
|
{
|
|
|
|
return fYear >= 1 && fYear <= 9999 &&
|
|
fMonth >= 1 && fMonth <= 12 &&
|
|
fDay >= 1 && fDay <= 31 &&
|
|
fHour <= 23 &&
|
|
fMinute <= 59 &&
|
|
fSecond <= 59;
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
void dng_date_time::Clear ()
|
|
{
|
|
|
|
*this = dng_date_time ();
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static uint32 DateTimeParseU32 (const char *&s)
|
|
{
|
|
|
|
uint32 x = 0;
|
|
|
|
while (*s == ' ' || *s == ':')
|
|
s++;
|
|
|
|
while (*s >= '0' && *s <= '9')
|
|
{
|
|
x = SafeUint32Mult(x, 10);
|
|
x = SafeUint32Add(x, (uint32) (*(s++) - '0'));
|
|
}
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
bool dng_date_time::Parse (const char *s)
|
|
{
|
|
|
|
fYear = DateTimeParseU32 (s);
|
|
fMonth = DateTimeParseU32 (s);
|
|
fDay = DateTimeParseU32 (s);
|
|
fHour = DateTimeParseU32 (s);
|
|
fMinute = DateTimeParseU32 (s);
|
|
fSecond = DateTimeParseU32 (s);
|
|
|
|
return IsValid ();
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
dng_string dng_time_zone::Encode_ISO_8601 () const
|
|
{
|
|
|
|
dng_string result;
|
|
|
|
if (IsValid ())
|
|
{
|
|
|
|
if (OffsetMinutes () == 0)
|
|
{
|
|
|
|
result.Set ("Z");
|
|
|
|
}
|
|
|
|
else
|
|
{
|
|
|
|
char s [64];
|
|
|
|
int offset = OffsetMinutes ();
|
|
|
|
if (offset > 0)
|
|
{
|
|
|
|
sprintf (s, "+%02d:%02d", offset / 60, offset % 60);
|
|
|
|
}
|
|
|
|
else
|
|
{
|
|
|
|
offset = -offset;
|
|
|
|
sprintf (s, "-%02d:%02d", offset / 60, offset % 60);
|
|
|
|
}
|
|
|
|
result.Set (s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
dng_date_time_info::dng_date_time_info ()
|
|
|
|
: fDateOnly (true)
|
|
, fDateTime ()
|
|
, fSubseconds ()
|
|
, fTimeZone ()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
bool dng_date_time_info::IsValid () const
|
|
{
|
|
|
|
return fDateTime.IsValid ();
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
void dng_date_time_info::SetDate (uint32 year,
|
|
uint32 month,
|
|
uint32 day)
|
|
{
|
|
|
|
fDateTime.fYear = year;
|
|
fDateTime.fMonth = month;
|
|
fDateTime.fDay = day;
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
void dng_date_time_info::SetTime (uint32 hour,
|
|
uint32 minute,
|
|
uint32 second)
|
|
{
|
|
|
|
fDateOnly = false;
|
|
|
|
fDateTime.fHour = hour;
|
|
fDateTime.fMinute = minute;
|
|
fDateTime.fSecond = second;
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
void dng_date_time_info::Decode_ISO_8601 (const char *s)
|
|
{
|
|
|
|
Clear ();
|
|
|
|
uint32 len = (uint32) strlen (s);
|
|
|
|
if (!len)
|
|
{
|
|
return;
|
|
}
|
|
|
|
unsigned year = 0;
|
|
unsigned month = 0;
|
|
unsigned day = 0;
|
|
|
|
if (sscanf (s,
|
|
"%u-%u-%u",
|
|
&year,
|
|
&month,
|
|
&day) != 3)
|
|
{
|
|
return;
|
|
}
|
|
|
|
SetDate ((uint32) year,
|
|
(uint32) month,
|
|
(uint32) day);
|
|
|
|
if (fDateTime.NotValid ())
|
|
{
|
|
Clear ();
|
|
return;
|
|
}
|
|
|
|
for (uint32 j = 0; j < len; j++)
|
|
{
|
|
|
|
if (s [j] == 'T')
|
|
{
|
|
|
|
unsigned hour = 0;
|
|
unsigned minute = 0;
|
|
unsigned second = 0;
|
|
|
|
int items = sscanf (s + j + 1,
|
|
"%u:%u:%u",
|
|
&hour,
|
|
&minute,
|
|
&second);
|
|
|
|
if (items >= 2 && items <= 3)
|
|
{
|
|
|
|
SetTime ((uint32) hour,
|
|
(uint32) minute,
|
|
(uint32) second);
|
|
|
|
if (fDateTime.NotValid ())
|
|
{
|
|
Clear ();
|
|
return;
|
|
}
|
|
|
|
if (items == 3)
|
|
{
|
|
|
|
for (uint32 k = j + 1; k < len; k++)
|
|
{
|
|
|
|
if (s [k] == '.')
|
|
{
|
|
|
|
while (++k < len && s [k] >= '0' && s [k] <= '9')
|
|
{
|
|
|
|
char ss [2];
|
|
|
|
ss [0] = s [k];
|
|
ss [1] = 0;
|
|
|
|
fSubseconds.Append (ss);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (uint32 k = j + 1; k < len; k++)
|
|
{
|
|
|
|
if (s [k] == 'Z')
|
|
{
|
|
|
|
fTimeZone.SetOffsetMinutes (0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (s [k] == '+' || s [k] == '-')
|
|
{
|
|
|
|
int32 sign = (s [k] == '-' ? -1 : 1);
|
|
|
|
unsigned tzhour = 0;
|
|
unsigned tzmin = 0;
|
|
|
|
if (sscanf (s + k + 1,
|
|
"%u:%u",
|
|
&tzhour,
|
|
&tzmin) > 0)
|
|
{
|
|
|
|
fTimeZone.SetOffsetMinutes (sign * (tzhour * 60 + tzmin));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
dng_string dng_date_time_info::Encode_ISO_8601 () const
|
|
{
|
|
|
|
dng_string result;
|
|
|
|
if (IsValid ())
|
|
{
|
|
|
|
char s [256];
|
|
|
|
sprintf (s,
|
|
"%04u-%02u-%02u",
|
|
(unsigned) fDateTime.fYear,
|
|
(unsigned) fDateTime.fMonth,
|
|
(unsigned) fDateTime.fDay);
|
|
|
|
result.Set (s);
|
|
|
|
if (!fDateOnly)
|
|
{
|
|
|
|
sprintf (s,
|
|
"T%02u:%02u:%02u",
|
|
(unsigned) fDateTime.fHour,
|
|
(unsigned) fDateTime.fMinute,
|
|
(unsigned) fDateTime.fSecond);
|
|
|
|
result.Append (s);
|
|
|
|
if (fSubseconds.NotEmpty ())
|
|
{
|
|
|
|
bool subsecondsValid = true;
|
|
|
|
uint32 len = fSubseconds.Length ();
|
|
|
|
for (uint32 index = 0; index < len; index++)
|
|
{
|
|
|
|
if (fSubseconds.Get () [index] < '0' ||
|
|
fSubseconds.Get () [index] > '9')
|
|
{
|
|
subsecondsValid = false;
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
if (subsecondsValid)
|
|
{
|
|
result.Append (".");
|
|
result.Append (fSubseconds.Get ());
|
|
}
|
|
|
|
}
|
|
|
|
if (gDNGUseFakeTimeZonesInXMP)
|
|
{
|
|
|
|
// Kludge: Early versions of the XMP toolkit assume Zulu time
|
|
// if the time zone is missing. It is safer for fill in the
|
|
// local time zone.
|
|
|
|
dng_time_zone tempZone = fTimeZone;
|
|
|
|
if (tempZone.NotValid ())
|
|
{
|
|
tempZone = LocalTimeZone (fDateTime);
|
|
}
|
|
|
|
result.Append (tempZone.Encode_ISO_8601 ().Get ());
|
|
|
|
}
|
|
|
|
else
|
|
{
|
|
|
|
// MWG: Now we don't fill in the local time zone. So only
|
|
// add the time zone if it is known and valid.
|
|
|
|
if (fTimeZone.IsValid ())
|
|
{
|
|
result.Append (fTimeZone.Encode_ISO_8601 ().Get ());
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
void dng_date_time_info::Decode_IPTC_Date (const char *s)
|
|
{
|
|
|
|
if (strlen (s) == 8)
|
|
{
|
|
|
|
unsigned year = 0;
|
|
unsigned month = 0;
|
|
unsigned day = 0;
|
|
|
|
if (sscanf (s,
|
|
"%4u%2u%2u",
|
|
&year,
|
|
&month,
|
|
&day) == 3)
|
|
{
|
|
|
|
SetDate ((uint32) year,
|
|
(uint32) month,
|
|
(uint32) day);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
dng_string dng_date_time_info::Encode_IPTC_Date () const
|
|
{
|
|
|
|
dng_string result;
|
|
|
|
if (IsValid ())
|
|
{
|
|
|
|
char s [64];
|
|
|
|
sprintf (s,
|
|
"%04u%02u%02u",
|
|
(unsigned) fDateTime.fYear,
|
|
(unsigned) fDateTime.fMonth,
|
|
(unsigned) fDateTime.fDay);
|
|
|
|
result.Set (s);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
void dng_date_time_info::Decode_IPTC_Time (const char *s)
|
|
{
|
|
|
|
if (strlen (s) == 11)
|
|
{
|
|
|
|
char time [12];
|
|
|
|
memcpy (time, s, sizeof (time));
|
|
|
|
if (time [6] == '+' ||
|
|
time [6] == '-')
|
|
{
|
|
|
|
int tzsign = (time [6] == '-') ? -1 : 1;
|
|
|
|
time [6] = 0;
|
|
|
|
unsigned hour = 0;
|
|
unsigned minute = 0;
|
|
unsigned second = 0;
|
|
unsigned tzhour = 0;
|
|
unsigned tzmin = 0;
|
|
|
|
if (sscanf (time,
|
|
"%2u%2u%2u",
|
|
&hour,
|
|
&minute,
|
|
&second) == 3 &&
|
|
sscanf (time + 7,
|
|
"%2u%2u",
|
|
&tzhour,
|
|
&tzmin) == 2)
|
|
{
|
|
|
|
dng_time_zone zone;
|
|
|
|
zone.SetOffsetMinutes (tzsign * (tzhour * 60 + tzmin));
|
|
|
|
if (zone.IsValid ())
|
|
{
|
|
|
|
SetTime ((uint32) hour,
|
|
(uint32) minute,
|
|
(uint32) second);
|
|
|
|
SetZone (zone);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (strlen (s) == 6)
|
|
{
|
|
|
|
unsigned hour = 0;
|
|
unsigned minute = 0;
|
|
unsigned second = 0;
|
|
|
|
if (sscanf (s,
|
|
"%2u%2u%2u",
|
|
&hour,
|
|
&minute,
|
|
&second) == 3)
|
|
{
|
|
|
|
SetTime ((uint32) hour,
|
|
(uint32) minute,
|
|
(uint32) second);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (strlen (s) == 4)
|
|
{
|
|
|
|
unsigned hour = 0;
|
|
unsigned minute = 0;
|
|
|
|
if (sscanf (s,
|
|
"%2u%2u",
|
|
&hour,
|
|
&minute) == 2)
|
|
{
|
|
|
|
SetTime ((uint32) hour,
|
|
(uint32) minute,
|
|
0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
dng_string dng_date_time_info::Encode_IPTC_Time () const
|
|
{
|
|
|
|
dng_string result;
|
|
|
|
if (IsValid () && !fDateOnly)
|
|
{
|
|
|
|
char s [64];
|
|
|
|
if (fTimeZone.IsValid ())
|
|
{
|
|
|
|
sprintf (s,
|
|
"%02u%02u%02u%c%02u%02u",
|
|
(unsigned) fDateTime.fHour,
|
|
(unsigned) fDateTime.fMinute,
|
|
(unsigned) fDateTime.fSecond,
|
|
(int) (fTimeZone.OffsetMinutes () >= 0 ? '+' : '-'),
|
|
(unsigned) (Abs_int32 (fTimeZone.OffsetMinutes ()) / 60),
|
|
(unsigned) (Abs_int32 (fTimeZone.OffsetMinutes ()) % 60));
|
|
|
|
}
|
|
|
|
else
|
|
{
|
|
|
|
sprintf (s,
|
|
"%02u%02u%02u",
|
|
(unsigned) fDateTime.fHour,
|
|
(unsigned) fDateTime.fMinute,
|
|
(unsigned) fDateTime.fSecond);
|
|
|
|
}
|
|
|
|
result.Set (s);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static dng_mutex gDateTimeMutex ("gDateTimeMutex");
|
|
|
|
/*****************************************************************************/
|
|
|
|
void CurrentDateTimeAndZone (dng_date_time_info &info)
|
|
{
|
|
|
|
time_t sec;
|
|
|
|
time (&sec);
|
|
|
|
tm t;
|
|
tm zt;
|
|
|
|
{
|
|
|
|
dng_lock_mutex lock (&gDateTimeMutex);
|
|
|
|
t = *localtime (&sec);
|
|
zt = *gmtime (&sec);
|
|
|
|
}
|
|
|
|
dng_date_time dt;
|
|
|
|
dt.fYear = t.tm_year + 1900;
|
|
dt.fMonth = t.tm_mon + 1;
|
|
dt.fDay = t.tm_mday;
|
|
dt.fHour = t.tm_hour;
|
|
dt.fMinute = t.tm_min;
|
|
dt.fSecond = t.tm_sec;
|
|
|
|
info.SetDateTime (dt);
|
|
|
|
int tzHour = t.tm_hour - zt.tm_hour;
|
|
int tzMin = t.tm_min - zt.tm_min;
|
|
|
|
bool zonePositive = (t.tm_year > zt.tm_year) ||
|
|
(t.tm_year == zt.tm_year && t.tm_yday > zt.tm_yday) ||
|
|
(t.tm_year == zt.tm_year && t.tm_yday == zt.tm_yday && tzHour > 0) ||
|
|
(t.tm_year == zt.tm_year && t.tm_yday == zt.tm_yday && tzHour == 0 && tzMin >= 0);
|
|
|
|
tzMin += tzHour * 60;
|
|
|
|
if (zonePositive)
|
|
{
|
|
|
|
while (tzMin < 0)
|
|
tzMin += 24 * 60;
|
|
|
|
}
|
|
|
|
else
|
|
{
|
|
|
|
while (tzMin > 0)
|
|
tzMin -= 24 * 60;
|
|
|
|
}
|
|
|
|
dng_time_zone zone;
|
|
|
|
zone.SetOffsetMinutes (tzMin);
|
|
|
|
info.SetZone (zone);
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
void DecodeUnixTime (uint32 unixTime, dng_date_time &dt)
|
|
{
|
|
|
|
time_t sec = (time_t) unixTime;
|
|
|
|
tm t;
|
|
|
|
{
|
|
|
|
dng_lock_mutex lock (&gDateTimeMutex);
|
|
|
|
#if qMacOS && !defined(__MACH__)
|
|
|
|
// Macintosh CFM stores time in local time zone.
|
|
|
|
tm *tp = localtime (&sec);
|
|
|
|
#else
|
|
|
|
// Macintosh Mach-O and Windows stores time in Zulu time.
|
|
|
|
tm *tp = gmtime (&sec);
|
|
|
|
#endif
|
|
|
|
if (!tp)
|
|
{
|
|
dt.Clear ();
|
|
return;
|
|
}
|
|
|
|
t = *tp;
|
|
|
|
}
|
|
|
|
dt.fYear = t.tm_year + 1900;
|
|
dt.fMonth = t.tm_mon + 1;
|
|
dt.fDay = t.tm_mday;
|
|
dt.fHour = t.tm_hour;
|
|
dt.fMinute = t.tm_min;
|
|
dt.fSecond = t.tm_sec;
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
dng_time_zone LocalTimeZone (const dng_date_time &dt)
|
|
{
|
|
|
|
dng_time_zone result;
|
|
|
|
if (dt.IsValid ())
|
|
{
|
|
|
|
#if qMacOS
|
|
|
|
CFTimeZoneRef zoneRef = CFTimeZoneCopyDefault ();
|
|
|
|
CFReleaseHelper<CFTimeZoneRef> zoneRefDeleter (zoneRef);
|
|
|
|
if (zoneRef)
|
|
{
|
|
|
|
// New path that doesn't use deprecated CFGregorian-based APIs.
|
|
|
|
CFCalendarRef calendar =
|
|
CFCalendarCreateWithIdentifier (kCFAllocatorDefault,
|
|
kCFGregorianCalendar);
|
|
|
|
CFReleaseHelper<CFCalendarRef> calendarDeleter (calendar);
|
|
|
|
CFAbsoluteTime absTime;
|
|
|
|
if (CFCalendarComposeAbsoluteTime (calendar,
|
|
&absTime,
|
|
"yMdHms",
|
|
dt.fYear,
|
|
dt.fMonth,
|
|
dt.fDay,
|
|
dt.fHour,
|
|
dt.fMinute,
|
|
dt.fSecond))
|
|
{
|
|
|
|
CFTimeInterval secondsDelta = CFTimeZoneGetSecondsFromGMT (zoneRef, absTime);
|
|
|
|
result.SetOffsetSeconds (Round_int32 (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;
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
dng_date_time_storage_info::dng_date_time_storage_info ()
|
|
|
|
: fOffset (kDNGStreamInvalidOffset )
|
|
, fFormat (dng_date_time_format_unknown)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
dng_date_time_storage_info::dng_date_time_storage_info (uint64 offset,
|
|
dng_date_time_format format)
|
|
|
|
: fOffset (offset)
|
|
, fFormat (format)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
bool dng_date_time_storage_info::IsValid () const
|
|
{
|
|
|
|
return fOffset != kDNGStreamInvalidOffset;
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
uint64 dng_date_time_storage_info::Offset () const
|
|
{
|
|
|
|
if (!IsValid ())
|
|
ThrowProgramError ();
|
|
|
|
return fOffset;
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
dng_date_time_format dng_date_time_storage_info::Format () const
|
|
{
|
|
|
|
if (!IsValid ())
|
|
ThrowProgramError ();
|
|
|
|
return fFormat;
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|