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
34class 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
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
115class 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
140		dng_time_zone ()
141			:	fOffsetMinutes (kInvalidOffset)
142			{
143			}
144
145		void Clear ()
146			{
147			fOffsetMinutes = kInvalidOffset;
148			}
149
150		void SetOffsetHours (int32 offset)
151			{
152			fOffsetMinutes = SafeInt32Mult(offset, 60);
153			}
154
155		void SetOffsetMinutes (int32 offset)
156			{
157			fOffsetMinutes = offset;
158			}
159
160		void SetOffsetSeconds (int32 offset)
161			{
162			fOffsetMinutes = (offset > 0) ? ((offset + 30) / 60)
163										  : ((offset - 30) / 60);
164			}
165
166		bool IsValid () const
167			{
168			return fOffsetMinutes >= kMinOffsetMinutes &&
169				   fOffsetMinutes <= kMaxOffsetMinutes;
170			}
171
172		bool NotValid () const
173			{
174			return !IsValid ();
175			}
176
177		int32 OffsetMinutes () const
178			{
179			return fOffsetMinutes;
180			}
181
182		bool IsExactHourOffset () const
183			{
184			return IsValid () && ((fOffsetMinutes % 60) == 0);
185			}
186
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
200class 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
227		bool NotValid () const
228			{
229			return !IsValid ();
230			}
231
232		void Clear ()
233			{
234			*this = dng_date_time_info ();
235			}
236
237		const dng_date_time & DateTime () const
238			{
239			return fDateTime;
240			}
241
242		void SetDateTime (const dng_date_time &dt)
243			{
244			fDateOnly = false;
245			fDateTime = dt;
246			}
247
248		const dng_string & Subseconds () const
249			{
250			return fSubseconds;
251			}
252
253		void SetSubseconds (const dng_string &s)
254			{
255			fSubseconds = s;
256			}
257
258		const dng_time_zone & TimeZone () const
259			{
260			return fTimeZone;
261			}
262
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
297void CurrentDateTimeAndZone (dng_date_time_info &info);
298
299/*****************************************************************************/
300
301/// Convert UNIX "seconds since Jan 1, 1970" time to a dng_date_time
302
303void 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
312dng_time_zone LocalTimeZone (const dng_date_time &dt);
313
314/*****************************************************************************/
315
316/// Tag to encode date represenation format
317
318enum 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
333class 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
379extern bool gDNGUseFakeTimeZonesInXMP;
380
381/*****************************************************************************/
382
383#endif
384
385/*****************************************************************************/
386