Imported Upstream version 1.1.0.99.1
[platform/upstream/syncevolution.git] / src / synthesis / src / sysync / timezones.h
1 /*
2  *  File:         timezones.h
3  *
4  *  Author:       Beat Forster
5  *
6  *  Timezones conversion from/to linear time scale.
7  *
8  *  Copyright (c) 2004-2009 by Synthesis AG (www.synthesis.ch)
9  *
10  *  2004-04-18 : bfo : initial version
11  *
12  */
13
14 #ifndef TIMEZONES_H
15 #define TIMEZONES_H
16
17 #include <string>
18 #include <list>
19
20 #include "lineartime.h"
21 #include "debuglogger.h"
22
23 #ifdef MUTEX_SUPPORT
24   #include "platform_mutex.h"
25 #endif
26
27
28 using namespace std; // for string and list
29
30 namespace sysync {
31
32 // include the built-in time zone table
33 #ifndef NO_BUILTIN_TZ
34         #include "tz_table.h"
35 #endif
36
37 /// time zone table entry definition
38 typedef struct tChangeStruct {
39           short wMonth;
40           short wDayOfWeek;
41           short wNth;      // nth occurance
42           short wHour;
43           short wMinute;
44
45           tChangeStruct() :
46             wMonth(0),
47             wDayOfWeek(0),
48             wNth(0),
49             wHour(0),
50             wMinute(0)
51           {}
52
53           tChangeStruct(short aMonth,
54                         short aDayOfWeek,
55                         short aNth,
56                         short aHour,
57                         short aMinute) :
58             wMonth(aMonth),
59             wDayOfWeek(aDayOfWeek),
60             wNth(aNth),
61             wHour(aHour),
62             wMinute(aMinute)
63             {}
64         } tChange;
65
66
67 class tz_entry {
68         public:
69           std::string name;          /**< name, same as TZID in
70                                         VTIMEZONE, e.g. CET/CEST or
71                                         /softwarestudio.org/Tzfile/Europe/Berlin;
72                                         see also dst/stdName */
73           std::string stdName;       /**< optional standard time name, e.g. CEST; must be
74                                         set if "name" is not a concatenation of
75                                         standard and daylight name (CET/CEST);
76                                         the vCalendar 1.0 code relies on that */
77           std::string dstName;       /**< used instead of splitting
78                                         "name" if (and only if)
79                                         stdName is set; may be empty
80                                         in zones without daylight
81                                         saving */
82           std::string location;      /**< location string as used in Olson TZID, e.g. Europe/Berlin */
83           short       bias;          /**< minutes difference to UTC (west negative, east positive */
84           short       biasDST;       /**< minutes difference to bias (not UTC!) */
85           std::string ident;         /**< see FoundTZ() */
86           std::string dynYear;       /**< if this time zone rule is assigned to a specific year range */
87           tChange     dst;           /**< describes when daylight saving time will become active */
88           tChange     std;           /**< describes when standard time will become active */
89           bool        groupEnd;      /**< true if the entry which follows this one belongs to a different zone or last entry */
90
91           tz_entry() :
92             bias(0),
93             biasDST(0),
94             groupEnd(true)
95           {}
96
97           tz_entry( const std::string &aName,
98                     short              aBias,
99                     short              aBiasDST,
100                     const std::string &aIdent,
101                     const std::string &aDynYear,
102                     const tChange     &aDst,
103                     const tChange     &aStd,
104                     bool               aGroupEnd ) :
105             name(aName),
106             bias(aBias),
107             biasDST(aBiasDST),
108             ident(aIdent),
109             dynYear(aDynYear),
110             dst(aDst),
111             std(aStd),
112             groupEnd(aGroupEnd)
113             {}
114 };
115
116
117
118
119
120 //const int DST_Bias= 60; // General DST offset (in minutes)
121
122 // Symbian timezone categories
123 // visible for all other systems as well
124 #ifndef __EPOC_OS__
125   enum TDaylightSavingZone {
126     EDstHome    =0x40000000,
127     EDstNone    =0,
128     EDstEuropean=1,
129     EDstNorthern=2,
130     EDstSouthern=4
131   };
132 #endif
133
134
135 // Offset mask
136 const uInt32 TCTX_OFFSETMASK = 0x0000FFFF;
137
138 // time context flags
139 // - symbolic zone flag
140 const uInt32 TCTX_SYMBOLIC_TZ= 0x00010000;
141 // - rendering flags
142 const uInt32 TCTX_DATEONLY   = 0x00020000;
143 const uInt32 TCTX_TIMEONLY   = 0x00040000;
144 const uInt32 TCTX_DURATION   = 0x00080000;
145
146 const uInt32 TCTX_RFLAGMASK = TCTX_DATEONLY+TCTX_TIMEONLY+TCTX_DURATION;
147
148 //! Get signed minute offset
149 sInt16  TCTX_MINOFFSET( timecontext_t tctx );
150
151 //! Get time zone enum
152 TTimeZones TCTX_TZENUM( timecontext_t tctx );
153
154
155 // macro to get time zone context
156 #define TCTX_ENUMCONTEXT( tzenum ) ((timecontext_t)      ((tzenum) | TCTX_SYMBOLIC_TZ))
157 #define TCTX_UNKNOWN                           TCTX_ENUMCONTEXT( tctx_tz_unknown )
158 #define TCTX_SYSTEM                            TCTX_ENUMCONTEXT( tctx_tz_system  )
159 #define TCTX_UTC                               TCTX_ENUMCONTEXT( tctx_tz_UTC  )
160 #define TCTX_OFFSCONTEXT( offs )   ((timecontext_t)((sInt16)(offs) & TCTX_OFFSETMASK ))
161
162
163 /*
164 // macro to get time zone and other flags
165 #define TCTX_IS_TZ( tctx )         ((bool)(tctx  & TCTX_SYMBOLIC_TZ))
166 #define TCTX_IS_DATEONLY( tctx )   ((bool)(tctx  & TCTX_DATEONLY   ))
167 */
168
169 //! Check if <tctx> is a symbolic TZ info
170 bool TCTX_IS_TZ      ( timecontext_t tctx );
171
172 // Check if <tctx> is a built-in symbolic TZ info
173 bool TCTX_IS_BUILTIN ( timecontext_t tctx );
174
175 //! Check if <tctx> has TCTX_DATEONLY mode set
176 bool TCTX_IS_DATEONLY( timecontext_t tctx );
177
178 //! Check if <tctx> has TCTX_TIMEONLY mode set
179 bool TCTX_IS_TIMEONLY( timecontext_t tctx );
180
181 //! Check if <tctx> has TCTX_DURATION mode set
182 bool TCTX_IS_DURATION( timecontext_t tctx );
183
184 //! Check if <tctx> is a unknown time zone
185 bool TCTX_IS_UNKNOWN ( timecontext_t tctx );
186
187 //! Check if <tctx> is the system time zone
188 bool TCTX_IS_SYSTEM  ( timecontext_t tctx );
189
190 //! Check if <tctx> is the UTC time zone
191 bool TCTX_IS_UTC  ( timecontext_t tctx );
192
193 //! result is render flags from <aRFlagContext> with zone info from <aZoneContext>
194 timecontext_t TCTX_JOIN_RFLAGS_TZ ( timecontext_t aRFlagContext, timecontext_t aZoneContext );
195
196
197
198 // ---- utility functions -------------------------------------------------------------
199 /*! Specific bias string. Unit: hours */
200 string BiasStr( int bias );
201
202 /*! Clear the DST info of <t> */
203 void ClrDST( tz_entry &t );
204
205
206 typedef std::list<tz_entry> TZList;
207
208 class GZones {
209   public:
210     GZones() {
211       #ifdef MUTEX_SUPPORT
212         muP= newMutex();
213       #endif
214
215       predefinedSysTZ= TCTX_UNKNOWN; // no predefined system time zone
216       sysTZ= predefinedSysTZ; // default to predefined zone, if none, this will be obtained from OS APIs
217       isDbg= false; // !!! IMPORTANT: do NOT enable this except for test targets, as it leads to recursions (debugPrintf calls time routines!)
218       fSystemZoneDefinitionsFinalized = false;
219
220       #ifdef SYDEBUG
221         getDbgMask  = 0;
222         getDbgLogger= NULL;
223       #endif
224     } // constructor
225     
226     /*! @brief populate GZones with system information
227      *
228      * Sets predefinedSysTZ, sysTZ and adds time zones
229      * to tzP, if that information can be found on the
230      * system.
231      *
232      * Returns false in case of a fatal error.
233      */
234     bool initialize();
235
236     /*! @brief log and/or add more GZones
237      *
238      * Called after config was read and normal debug logging
239      * is possible.
240      */
241     void loggingStarted();
242
243     /*! @brief find a matching time zone
244      *
245      * This returns the best match, with "better" defined as (best
246      * match first):
247      * - exact name AND exact rule set match
248      * - existing entry has a location (currently only the case for
249      *   time zones imported from libical) AND that location is part of the
250      *   name being searched for AND the rule matches
251      * - as before, but with the rule match
252      * - exact rule set match
253      *
254      * If there are multiple entries which are equally good, the first one
255      * is returned.
256      *
257      * When doing rule matching, the dynYear value of an existing
258      * entry has to match the current year as implemented by the
259      * FitYear() function in timezone.cpp. In most (all?) cases this
260      * has the effect that historic rules are skipped. Likewise,
261      * VTIMEZONE information sent out is based on the current rules
262      * for the zone, regardless of when the event itself takes place.
263      *
264      * This is approach is intentional: it helps avoid mismatches
265      * when historic rules of one zone match the current rules of
266      * another. Furthermore, it helps peers which do rule-based
267      * matching and only know the current rules of each zone.
268      *
269      * @param  aTZ         entry with rules and name set; ident is ignored
270      * @retval aContext    the matching time zone context ID; it always
271      *                     refers to the tz_entry without a dynYear
272      * @return true if match found
273      */
274     bool matchTZ(const tz_entry &aTZ, TDebugLogger *aLogP, timecontext_t &aContext);
275
276     class visitor {
277     public:
278       /** @return true to stop iterating */
279       virtual bool visit(const tz_entry &aTZ, timecontext_t aContext) = 0;
280             virtual ~visitor() {} // destructor
281     };
282
283     /*! @brief invoke visitor once for each time zone
284      * @return true if the visitor returned true
285      */
286     bool foreachTZ(visitor &v);
287
288     void ResetCache(void) {
289       sysTZ= predefinedSysTZ; // reset cached system time zone to make sure it is re-evaluated
290     }
291
292     #ifdef MUTEX_SUPPORT
293     #endif
294
295     TZList                    tzP; // the list of additional time zones
296     timecontext_t predefinedSysTZ; // can be set to a specific zone to override zone returned by OS API
297     timecontext_t           sysTZ; // the system's time zone, will be calculated,
298                                    // if set to tctx_tz_unknown
299     bool                    isDbg; // write debug information
300     bool fSystemZoneDefinitionsFinalized; // finalizeSystemZoneDefinitions() already called
301
302     #ifdef SYDEBUG
303       uInt32        getDbgMask; // allow debugging in a specific context
304       TDebugLogger* getDbgLogger;
305     #endif
306 }; // GZones
307
308
309
310 // visible for debugging only
311 timecontext_t SystemTZ( GZones *g, bool isDbg= false );
312 timecontext_t SelectTZ( TDaylightSavingZone zone, int bias, int biasDST, lineartime_t tNow,
313                                    bool isDbg= false );
314
315 // visible for platform_timezones.cpp/.mm
316 bool ContextForEntry( timecontext_t &aContext, tz_entry &t, bool chkNameFirst, GZones* g );
317 void Get_tChange( lineartime_t tim, tChange &v, bool asDate= false );
318
319
320
321 /*! Get <tz_entry> from <aContext>
322  *                   or <std>/<dst>
323  */
324 bool GetTZ( timecontext_t aContext,                        tz_entry &t, GZones* g, int year= 0 );
325 bool GetTZ( string std, string dst, int bias, int biasDST, tz_entry &t, GZones* g );
326
327 /*! Get the current year
328  */
329 sInt16 MyYear( GZones* g );
330
331
332 /*! Returns true, if the given TZ is existing already
333  *    <t>            tz_entry to search for:
334  *                   If <t.name> == ""  search for any entry with these values.
335  *                      <t.name> != ""  name must fit
336  *                   If <t.ident>== ""  search for any entry with these values
337  *                      <t.ident>!= ""  ident must fit
338  *                      <t.ident>== "?" search for the name <t.name> only.
339  *
340  *    <aName>        is <t.name> of the found record
341  *    <aContext>     is the assigned context
342  *    <g>            global list of additional time zones
343  *    <createIt>     create an entry, if not yet existing / default: false
344  *    <searchOffset> says, where to start searching       / default: at the beginning
345  */
346 bool FoundTZ( const tz_entry &t,
347               string        &aName,
348               timecontext_t &aContext,
349               GZones*       g,
350               bool          createIt    = false,
351               timecontext_t searchOffset= tctx_tz_unknown );
352
353
354 /*! Remove an existing entry
355  *  Currently, elements of the hard coded list can't be removed
356  */
357 bool RemoveTZ( const tz_entry &t, GZones* g );
358
359
360 /*! Is it a DST time zone ? (both months must be defined for DST mode) */
361 bool DSTCond( const tz_entry &t );
362
363 /*! Adjust to day number within month <m>, %% valid till year <y> 2099 */
364 void AdjustDay( sInt16 &d, sInt16 m, sInt16 y );
365
366 /*! Get lineartime_t of <t> for a given <year>, either from std <toDST> or vice versa */
367 lineartime_t DST_Switch( const tz_entry &t, int bias, sInt16 aYear, bool toDST );
368
369 /*! Convert time zone name into context
370  *  @param[in]  aName    : context name to resolve
371  *  @param[out] aContext : context for this aName
372  *  @param[in]  g        : global list of additional time zones
373  *
374  */
375 bool TimeZoneNameToContext( cAppCharP aName, timecontext_t &aContext, GZones* g );
376
377 /*! Convert context into time zone name, a preferred name can be given
378  *  @param[in]  aContext   : time context to resolve
379  *  @param[out] aName      : context name for this aContext
380  *  @param[in]  g          : global list of additional time zones
381  *  @param[in]  aPrefIdent : preferred name, if more than one is fitting
382  *
383  */
384 bool TimeZoneContextToName( timecontext_t aContext, string &aName, GZones* g, cAppCharP aPrefIdent= "" );
385
386
387
388 /*! get system's time zone context (i.e. resolve the TCTX_SYSTEM meta-context)
389  *  @param[in,out] aContext : context will be made non-meta, that is, if input is TCTX_SYSTEM,
390  *                            actual time zone will be determined.
391  *  @param[in] g            : global list of additional time zones
392  */
393 bool TzResolveMetaContext( timecontext_t &aContext, GZones* g );
394
395 /*! make time context non-symbolic (= calculate minute offset east of UTC for aRefTime)
396  *  but retain other time context flags in aContext
397  *  @param[in,out] aContext : context will be made non-symbolic, that is resolved to minute offset east of UTC
398  *  @param[in] aRefTime     : reference time point for resolving the offset
399  *  @param[in] aRefTimeUTC  : if set, reference time must be UTC,
400  *                            otherwise, reference time must be in context of aContext
401  *  @param[in] g            : global list of additional time zones
402  */
403 bool TzResolveContext( timecontext_t &aContext, lineartime_t aRefTime, bool aRefTimeUTC, GZones* g );
404
405 /*! calculate minute offset east of UTC for aRefTime
406  *  @param[in] aContext       : time context to resolve
407  *  @param[out] aMinuteOffset : receives minute offset east of UTC
408  *  @param[in] aRefTime       : reference time point for resolving the offset
409  *  @param[in] aRefTimeUTC    : if set, reference time must be UTC,
410  *                              otherwise, reference time must be in context of aContext
411  *  @param[in] g              : global list of additional time zones
412  */
413 bool TzResolveToOffset( timecontext_t aContext, sInt16      &aMinuteOffset,
414                                                 lineartime_t aRefTime,
415                                                 bool         aRefTimeUTC,
416                                                 GZones*      g );
417
418
419 /*! Offset between two contexts (in seconds)
420  *  Complex time zones (type "$") can't be currently resolved, they return false
421  *  @param[in] aSourceValue   : reference time for which the offset should be calculated
422  *  @param[in] aSourceContext : source time zone context
423  *  @param[in] aTargetContext : source time zone context
424  *  @param[out] sDiff         : receives offset east of UTC in seconds
425  *  @param[in] g              : global list of additional time zones
426  *  @param[in] aDefaultContext: default context to use if source or target is TCTX_UNKNOWN
427  */
428 bool TzOffsetSeconds( lineartime_t aSourceValue, timecontext_t aSourceContext,
429                                                  timecontext_t aTargetContext,
430                                                  sInt32        &sDiff,
431                                                  GZones*       g,
432                                                  timecontext_t aDefaultContext= TCTX_UNKNOWN);
433
434
435
436 /*! Converts timestamp value from one zone to another
437  *  Complex time zones (type "$") can't be currently resolved, they return false
438  *  @param[in/out] aValue     : will be converted from source context to target context
439  *  @param[in] aSourceContext : source time zone context
440  *  @param[in] aTargetContext : source time zone context
441  *  @param[in] g              : global list of additional time zones
442  *  @param[in] aDefaultContext: default context to use if source or target is TCTX_UNKNOWN
443  */
444 bool TzConvertTimestamp( lineartime_t &aValue,   timecontext_t aSourceContext,
445                                                  timecontext_t aTargetContext,
446                                                  GZones*       g,
447                                                  timecontext_t aDefaultContext = TCTX_UNKNOWN);
448
449
450 /*! Prototypes for platform-specific implementation of time-zone-related routines
451  *  which are implemented in platform_time.cpp
452  */
453
454 /*! @brief get system real time
455  *  @return system's real time in lineartime_t scale, in specified time zone context
456  *  @param[in] aTimeContext : desired output time zone
457  *  @param[in] g            : global list of additional time zones
458  *  @param[in] aNoOffset    : no offset calculation, if true (to avoid recursive calls)
459  */
460 lineartime_t getSystemNowAs( timecontext_t aTimeContext, GZones* g, bool aNoOffset= false );
461
462
463 /*! Prototypes for platform-specific implementation of time-zone-related routines
464  *  which are implemented in platform_timezones.cpp/.mm
465  */
466
467 /*! @brief platform specific loading of time zone definitions
468  *  @return true if this list is considered complete (i.e. no built-in zones should be used additionally)
469  *  @param[in/out] aGZones : the GZones object where system zones should be loaded into
470  *  @note this is called at construction of the SyncAppBase before any logging facilities are
471  *        available. This routine should load enough time zone information such that config
472  *        can be read and conversion between UTC and system local time is possible.
473  *        Use finalizeSystemZoneDefinitions() to add time zones with full logging available.
474  */
475 bool loadSystemZoneDefinitions( GZones* aGZones );
476
477 /*! @brief second opportunity to load platform specific time zone definitions with logging available (and config already parsed)
478  *  Called only once per GZones instance.
479  *  @param[in/out] aGZones : the GZones object where additional system zones should be loaded into
480  */
481 void finalizeSystemZoneDefinitions( GZones* aGZones );
482
483 /*! @brief get current system time zone
484  *  @return true if successful
485  *  @param[out] aContext : the time zone context representing the current system time zone.
486  *  @param[in] aGZones : the GZones object.
487  */
488 bool getSystemTimeZoneContext( timecontext_t &aContext, GZones* aGZones );
489
490
491
492 } // namespace sysync
493
494 #endif
495 /* eof */