/*****************************************************************************/ // 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.h#1 $ */ /* $DateTime: 2012/05/30 13:28:51 $ */ /* $Change: 832332 $ */ /* $Author: tknoll $ */ /** \file * Functions and classes for working with dates and times in DNG files. */ /*****************************************************************************/ #ifndef __dng_date_time__ #define __dng_date_time__ /*****************************************************************************/ #include "dng_classes.h" #include "dng_string.h" #include "dng_types.h" /*****************************************************************************/ /// \brief Class for holding a date/time and converting to and from relevant /// date/time formats class dng_date_time { public: uint32 fYear; uint32 fMonth; uint32 fDay; uint32 fHour; uint32 fMinute; uint32 fSecond; public: /// Construct an invalid date/time dng_date_time (); /// Construct a date/time with specific values. /// \param year Year to use as actual integer value, such as 2006. /// \param month Month to use from 1 - 12, where 1 is January. /// \param day Day of month to use from 1 -31, where 1 is the first. /// \param hour Hour of day to use from 0 - 23, where 0 is midnight. /// \param minute Minute of hour to use from 0 - 59. /// \param second Second of minute to use from 0 - 59. dng_date_time (uint32 year, uint32 month, uint32 day, uint32 hour, uint32 minute, uint32 second); /// Predicate to determine if a date is valid. /// \retval true if all fields are within range. bool IsValid () const; /// Predicate to determine if a date is invalid. /// \retval true if any field is out of range. bool NotValid () const { return !IsValid (); } /// Equal operator. bool operator== (const dng_date_time &dt) const { return fYear == dt.fYear && fMonth == dt.fMonth && fDay == dt.fDay && fHour == dt.fHour && fMinute == dt.fMinute && fSecond == dt.fSecond; } // Not-equal operator. bool operator!= (const dng_date_time &dt) const { return !(*this == dt); } /// Set date to an invalid value. void Clear (); /// Parse an EXIF format date string. /// \param s Input date string to parse. /// \retval true if date was parsed successfully and date is valid. bool Parse (const char *s); }; /*****************************************************************************/ /// \brief Class for holding a time zone. class dng_time_zone { private: enum { kMaxOffsetHours = 15, kMinOffsetHours = -kMaxOffsetHours, kMaxOffsetMinutes = kMaxOffsetHours * 60, kMinOffsetMinutes = kMinOffsetHours * 60, kInvalidOffset = kMinOffsetMinutes - 1 }; // Offset from GMT in minutes. Positive numbers are // ahead of GMT, negative number are behind GMT. int32 fOffsetMinutes; public: dng_time_zone () : fOffsetMinutes (kInvalidOffset) { } void Clear () { fOffsetMinutes = kInvalidOffset; } void SetOffsetHours (int32 offset) { fOffsetMinutes = SafeInt32Mult(offset, 60); } void SetOffsetMinutes (int32 offset) { fOffsetMinutes = offset; } void SetOffsetSeconds (int32 offset) { fOffsetMinutes = (offset > 0) ? ((offset + 30) / 60) : ((offset - 30) / 60); } bool IsValid () const { return fOffsetMinutes >= kMinOffsetMinutes && fOffsetMinutes <= kMaxOffsetMinutes; } bool NotValid () const { return !IsValid (); } int32 OffsetMinutes () const { return fOffsetMinutes; } bool IsExactHourOffset () const { return IsValid () && ((fOffsetMinutes % 60) == 0); } int32 ExactHourOffset () const { return fOffsetMinutes / 60; } dng_string Encode_ISO_8601 () const; }; /*****************************************************************************/ /// \brief Class for holding complete data/time/zone information. class dng_date_time_info { private: // Is only the date valid and not the time? bool fDateOnly; // Date and time. dng_date_time fDateTime; // Subseconds string (stored in a separate tag in EXIF). dng_string fSubseconds; // Time zone, if known. dng_time_zone fTimeZone; public: dng_date_time_info (); bool IsValid () const; bool NotValid () const { return !IsValid (); } void Clear () { *this = dng_date_time_info (); } const dng_date_time & DateTime () const { return fDateTime; } void SetDateTime (const dng_date_time &dt) { fDateOnly = false; fDateTime = dt; } const dng_string & Subseconds () const { return fSubseconds; } void SetSubseconds (const dng_string &s) { fSubseconds = s; } const dng_time_zone & TimeZone () const { return fTimeZone; } void SetZone (const dng_time_zone &zone) { fTimeZone = zone; } void Decode_ISO_8601 (const char *s); dng_string Encode_ISO_8601 () const; void Decode_IPTC_Date (const char *s); dng_string Encode_IPTC_Date () const; void Decode_IPTC_Time (const char *s); dng_string Encode_IPTC_Time () const; private: void SetDate (uint32 year, uint32 month, uint32 day); void SetTime (uint32 hour, uint32 minute, uint32 second); }; /*****************************************************************************/ /// Get the current date/time and timezone. /// \param info Receives current data/time/zone. void CurrentDateTimeAndZone (dng_date_time_info &info); /*****************************************************************************/ /// Convert UNIX "seconds since Jan 1, 1970" time to a dng_date_time void DecodeUnixTime (uint32 unixTime, dng_date_time &dt); /*****************************************************************************/ /// Return timezone of current location at a given date. /// \param dt Date at which to compute timezone difference. (For example, used /// to determine Daylight Savings, etc.) /// \retval Time zone for date/time dt. dng_time_zone LocalTimeZone (const dng_date_time &dt); /*****************************************************************************/ /// Tag to encode date represenation format enum dng_date_time_format { dng_date_time_format_unknown = 0, /// Date format not known dng_date_time_format_exif = 1, /// EXIF date string dng_date_time_format_unix_little_endian = 2, /// 32-bit UNIX time as 4-byte little endian dng_date_time_format_unix_big_endian = 3 /// 32-bit UNIX time as 4-byte big endian }; /*****************************************************************************/ /// \brief Store file offset from which date was read. /// /// Used internally by Adobe to update date in original file. /// \warning Use at your own risk. class dng_date_time_storage_info { private: uint64 fOffset; dng_date_time_format fFormat; public: /// The default constructor initializes to an invalid state. dng_date_time_storage_info (); /// Construct with file offset and date format. dng_date_time_storage_info (uint64 offset, dng_date_time_format format); /// Predicate to determine if an offset is valid. /// \retval true if offset is valid. bool IsValid () const; // The accessors throw if the data is not valid. /// Getter for offset in file. /// \exception dng_exception with fErrorCode equal to dng_error_unknown /// if offset is not valid. uint64 Offset () const; /// Get for format date was originally stored in file. Throws a /// dng_error_unknown exception if offset is invalid. /// \exception dng_exception with fErrorCode equal to dng_error_unknown /// if offset is not valid. dng_date_time_format Format () const; }; /*****************************************************************************/ // Kludge: Global boolean to turn on fake time zones in XMP for old software. extern bool gDNGUseFakeTimeZonesInXMP; /*****************************************************************************/ #endif /*****************************************************************************/