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