1 /*****************************************************************************/ 2 // Copyright 2006-2019 Adobe Systems Incorporated 3 // All Rights Reserved. 4 // 5 // NOTICE: Adobe permits you to use, modify, and distribute this file in 6 // accordance with the terms of the Adobe license agreement accompanying it. 7 /*****************************************************************************/ 8 9 /** \file 10 * Functions and classes for working with dates and times in DNG files. 11 */ 12 13 /*****************************************************************************/ 14 15 #ifndef __dng_date_time__ 16 #define __dng_date_time__ 17 18 /*****************************************************************************/ 19 20 #include "dng_classes.h" 21 #include "dng_string.h" 22 #include "dng_types.h" 23 24 /*****************************************************************************/ 25 26 /// \brief Class for holding a date/time and converting to and from relevant 27 /// date/time formats 28 29 class dng_date_time 30 { 31 32 public: 33 34 uint32 fYear; 35 uint32 fMonth; 36 uint32 fDay; 37 uint32 fHour; 38 uint32 fMinute; 39 uint32 fSecond; 40 41 public: 42 43 /// Construct an invalid date/time 44 45 dng_date_time (); 46 47 /// Construct a date/time with specific values. 48 /// \param year Year to use as actual integer value, such as 2006. 49 /// \param month Month to use from 1 - 12, where 1 is January. 50 /// \param day Day of month to use from 1 -31, where 1 is the first. 51 /// \param hour Hour of day to use from 0 - 23, where 0 is midnight. 52 /// \param minute Minute of hour to use from 0 - 59. 53 /// \param second Second of minute to use from 0 - 59. 54 55 dng_date_time (uint32 year, 56 uint32 month, 57 uint32 day, 58 uint32 hour, 59 uint32 minute, 60 uint32 second); 61 62 /// Predicate to determine if a date is valid. 63 /// \retval true if all fields are within range. 64 65 bool IsValid () const; 66 67 /// Predicate to determine if a date is invalid. 68 /// \retval true if any field is out of range. 69 NotValid()70 bool NotValid () const 71 { 72 return !IsValid (); 73 } 74 75 /// Equal operator. 76 77 bool operator== (const dng_date_time &dt) const 78 { 79 return fYear == dt.fYear && 80 fMonth == dt.fMonth && 81 fDay == dt.fDay && 82 fHour == dt.fHour && 83 fMinute == dt.fMinute && 84 fSecond == dt.fSecond; 85 } 86 87 // Not-equal operator. 88 89 bool operator!= (const dng_date_time &dt) const 90 { 91 return !(*this == dt); 92 } 93 94 /// Set date to an invalid value. 95 96 void Clear (); 97 98 /// Parse an EXIF format date string. 99 /// \param s Input date string to parse. 100 /// \retval true if date was parsed successfully and date is valid. 101 102 bool Parse (const char *s); 103 104 }; 105 106 /*****************************************************************************/ 107 108 /// \brief Class for holding a time zone. 109 110 class dng_time_zone 111 { 112 113 private: 114 115 enum 116 { 117 118 kMaxOffsetHours = 15, 119 kMinOffsetHours = -kMaxOffsetHours, 120 121 kMaxOffsetMinutes = kMaxOffsetHours * 60, 122 kMinOffsetMinutes = kMinOffsetHours * 60, 123 124 kInvalidOffset = kMinOffsetMinutes - 1 125 126 }; 127 128 // Offset from GMT in minutes. Positive numbers are 129 // ahead of GMT, negative number are behind GMT. 130 131 int32 fOffsetMinutes; 132 133 public: 134 dng_time_zone()135 dng_time_zone () 136 : fOffsetMinutes (kInvalidOffset) 137 { 138 } 139 Clear()140 void Clear () 141 { 142 fOffsetMinutes = kInvalidOffset; 143 } 144 SetOffsetHours(int32 offset)145 void SetOffsetHours (int32 offset) 146 { 147 fOffsetMinutes = offset * 60; 148 } 149 SetOffsetMinutes(int32 offset)150 void SetOffsetMinutes (int32 offset) 151 { 152 fOffsetMinutes = offset; 153 } 154 SetOffsetSeconds(int32 offset)155 void SetOffsetSeconds (int32 offset) 156 { 157 fOffsetMinutes = (offset > 0) ? ((offset + 30) / 60) 158 : ((offset - 30) / 60); 159 } 160 IsValid()161 bool IsValid () const 162 { 163 return fOffsetMinutes >= kMinOffsetMinutes && 164 fOffsetMinutes <= kMaxOffsetMinutes; 165 } 166 NotValid()167 bool NotValid () const 168 { 169 return !IsValid (); 170 } 171 OffsetMinutes()172 int32 OffsetMinutes () const 173 { 174 return fOffsetMinutes; 175 } 176 IsExactHourOffset()177 bool IsExactHourOffset () const 178 { 179 return IsValid () && ((fOffsetMinutes % 60) == 0); 180 } 181 ExactHourOffset()182 int32 ExactHourOffset () const 183 { 184 return fOffsetMinutes / 60; 185 } 186 187 dng_string Encode_ISO_8601 () const; 188 189 }; 190 191 /*****************************************************************************/ 192 193 /// \brief Class for holding complete data/time/zone information. 194 195 class dng_date_time_info 196 { 197 198 private: 199 200 // Is only the date valid and not the time? 201 202 bool fDateOnly; 203 204 // Date and time. 205 206 dng_date_time fDateTime; 207 208 // Subseconds string (stored in a separate tag in EXIF). 209 210 dng_string fSubseconds; 211 212 // Time zone, if known. 213 214 dng_time_zone fTimeZone; 215 216 public: 217 218 dng_date_time_info (); 219 220 bool IsValid () const; 221 NotValid()222 bool NotValid () const 223 { 224 return !IsValid (); 225 } 226 Clear()227 void Clear () 228 { 229 *this = dng_date_time_info (); 230 } 231 IsDateOnly()232 bool IsDateOnly () const 233 { 234 return fDateOnly; 235 } 236 DateTime()237 const dng_date_time & DateTime () const 238 { 239 return fDateTime; 240 } 241 SetDateTime(const dng_date_time & dt)242 void SetDateTime (const dng_date_time &dt) 243 { 244 fDateOnly = false; 245 fDateTime = dt; 246 } 247 Subseconds()248 const dng_string & Subseconds () const 249 { 250 return fSubseconds; 251 } 252 SetSubseconds(const dng_string & s)253 void SetSubseconds (const dng_string &s) 254 { 255 fSubseconds = s; 256 } 257 TimeZone()258 const dng_time_zone & TimeZone () const 259 { 260 return fTimeZone; 261 } 262 SetZone(const dng_time_zone & zone)263 void SetZone (const dng_time_zone &zone) 264 { 265 fTimeZone = zone; 266 } 267 ClearZone()268 void ClearZone () 269 { 270 fTimeZone.Clear (); 271 } 272 273 void SetOffsetTime (const dng_string &s); 274 275 dng_string OffsetTime () const; 276 277 void Decode_ISO_8601 (const char *s); 278 279 dng_string Encode_ISO_8601 () const; 280 281 void Decode_IPTC_Date (const char *s); 282 283 dng_string Encode_IPTC_Date () const; 284 285 void Decode_IPTC_Time (const char *s); 286 287 dng_string Encode_IPTC_Time () const; 288 289 private: 290 291 void SetDate (uint32 year, 292 uint32 month, 293 uint32 day); 294 295 void SetTime (uint32 hour, 296 uint32 minute, 297 uint32 second); 298 299 }; 300 301 /*****************************************************************************/ 302 303 /// Get the current date/time and timezone. 304 /// \param info Receives current data/time/zone. 305 306 void CurrentDateTimeAndZone (dng_date_time_info &info); 307 308 /*****************************************************************************/ 309 310 /// Convert UNIX "seconds since Jan 1, 1970" time to a dng_date_time 311 312 void DecodeUnixTime (uint32 unixTime, dng_date_time &dt); 313 314 /*****************************************************************************/ 315 316 /// Return timezone of current location at a given date. 317 /// \param dt Date at which to compute timezone difference. (For example, used 318 /// to determine Daylight Savings, etc.) 319 /// \retval Time zone for date/time dt. 320 321 dng_time_zone LocalTimeZone (const dng_date_time &dt); 322 323 /*****************************************************************************/ 324 325 /// Tag to encode date represenation format 326 327 enum dng_date_time_format 328 { 329 dng_date_time_format_unknown = 0, /// Date format not known 330 dng_date_time_format_exif = 1, /// EXIF date string 331 dng_date_time_format_unix_little_endian = 2, /// 32-bit UNIX time as 4-byte little endian 332 dng_date_time_format_unix_big_endian = 3 /// 32-bit UNIX time as 4-byte big endian 333 }; 334 335 /*****************************************************************************/ 336 337 /// \brief Store file offset from which date was read. 338 /// 339 /// Used internally by Adobe to update date in original file. 340 /// \warning Use at your own risk. 341 342 class dng_date_time_storage_info 343 { 344 345 private: 346 347 uint64 fOffset; 348 349 dng_date_time_format fFormat; 350 351 public: 352 353 /// The default constructor initializes to an invalid state. 354 355 dng_date_time_storage_info (); 356 357 /// Construct with file offset and date format. 358 359 dng_date_time_storage_info (uint64 offset, 360 dng_date_time_format format); 361 362 /// Predicate to determine if an offset is valid. 363 /// \retval true if offset is valid. 364 365 bool IsValid () const; 366 367 // The accessors throw if the data is not valid. 368 369 /// Getter for offset in file. 370 /// \exception dng_exception with fErrorCode equal to dng_error_unknown 371 /// if offset is not valid. 372 373 uint64 Offset () const; 374 375 /// Get for format date was originally stored in file. Throws a 376 /// dng_error_unknown exception if offset is invalid. 377 /// \exception dng_exception with fErrorCode equal to dng_error_unknown 378 /// if offset is not valid. 379 380 dng_date_time_format Format () const; 381 382 }; 383 384 /*****************************************************************************/ 385 386 #endif 387 388 /*****************************************************************************/ 389