Imported Upstream version 1.0beta2a
[platform/upstream/syncevolution.git] / src / synthesis / src / sysync_SDK / Sources / lineartime.cpp
1 /*
2  *  File:         lineartime.c
3  *
4  *  Author:                       Lukas Zeller (luz@synthesis.ch)
5  *
6  *  conversion from/to linear time scale.
7  *
8  *  Copyright (c) 2002-2009 by Synthesis AG (www.synthesis.ch)
9  *
10  *  2002-04-14 : luz : created from pascal source (plani.ch)
11  *
12  */
13 #include "prefix_file.h"
14 #include "sync_include.h"
15 #include "lineartime.h"
16 #include "timezones.h"
17
18 #if defined(SYSYNC_TOOL)
19   #include "syncappbase.h" // for CONSOLEPRINTF
20   #include "vtimezone.h" // for CONSOLEPRINTF
21 #endif
22
23 namespace sysync {
24
25 // Support for SySync Diagnostic Tool
26 #ifdef SYSYNC_TOOL
27
28 // convert between different time formats and zones
29 int timeConv(int argc, const char *argv[])
30 {
31   if (argc<0) {
32     // help requested
33     CONSOLEPRINTF(("  time <input zone> <output zone> [<input in ISO8601 or lineartime>]"));
34     CONSOLEPRINTF(("    Convert between time zone representations:"));
35     CONSOLEPRINTF(("     special input zone names: "));
36     CONSOLEPRINTF(("     - \"now\"       : input is current system time (no <input> required)"));
37     CONSOLEPRINTF(("     - \"floating\"  : floating time (when no zone from ISO8601 input"));
38     CONSOLEPRINTF(("     - \"vtimezone\" : output zone as VTIMEZONE"));
39     return EXIT_SUCCESS;
40   }
41
42   // check for argument
43   if (argc<2 || argc>3) {
44     CONSOLEPRINTF(("2 or 3 arguments required"));
45     return EXIT_FAILURE;
46   }
47   // mode
48   string inzone,outzone,s,z;
49   // internal representation
50   lineartime_t intime;
51   sInt16 minOffs;
52   timecontext_t incontext,outcontext;
53   GZones zones;
54   // get input mode
55   inzone=argv[0];
56   outzone=argv[1];
57   // check special "now" case
58   if (strucmp(inzone.c_str(),"now")==0) {
59     // input time is current time in system zone
60     incontext = TCTX_SYSTEM;
61     intime = getSystemNowAs(incontext,&zones);
62   }
63   else {
64     // get input context from name
65     if (!TimeZoneNameToContext(inzone.c_str(),incontext,&zones))
66       incontext=TCTX_UNKNOWN;
67     // input time from 3rd argument
68     if (argc!=3) {
69       CONSOLEPRINTF(("input time required as 3rd argument"));
70       return EXIT_FAILURE;
71     }
72     // try to parse as ISO8601
73     timecontext_t inpctx;
74     uInt16 n=ISO8601StrToTimestamp(argv[2],intime,inpctx);
75     if (n==0 || argv[2][n]!=0) {
76       // no ISO, read as lineartime
77       inpctx=TCTX_UNKNOWN;
78       n=StrToLongLong(argv[2],intime);
79       if (n==0) {
80         CONSOLEPRINTF(("input time must be either ISO8601 or decimal lineartime units"));
81         return EXIT_FAILURE;
82       }
83     }
84     if (!TCTX_IS_UNKNOWN(inpctx))
85       incontext=inpctx;
86   }
87   // get output context
88   if (strucmp(outzone.c_str(),"vtimezone")==0) {
89     // show input time zone as VTIMEZONE and DAYLIGHT (for current date)
90     intime = getSystemNowAs(incontext,&zones);
91     internalToVTIMEZONE(incontext,z,&zones);
92     CONSOLEPRINTF(("Input time zone represented as VTIMEZONE :\n\nBEGIN:VTIMEZONE\n%sEND:VTIMEZONE\n",z.c_str()));
93     timecontext_t stdoffs;
94     ContextToTzDaylight(incontext,intime,z,stdoffs,&zones);
95     s.erase(); ContextToISO8601StrAppend(s, stdoffs, true);
96     CONSOLEPRINTF(("Input time zone represented as TZ/DAYLIGHT :\n\nTZ:%s\nDAYLIGHT:%s\n",s.c_str(),z.c_str()));
97   }
98   else if (!TimeZoneNameToContext(outzone.c_str(),outcontext,&zones))
99     outcontext=TCTX_UNKNOWN;
100   // now show
101   CONSOLEPRINTF((""));
102   // - input
103   TimestampToISO8601Str(s, intime, incontext, true, true);
104   TimeZoneContextToName(incontext, z, &zones);
105   TzResolveToOffset(incontext, minOffs, intime, false, &zones);
106   CONSOLEPRINTF(("Input  : %-25s (%+03hd:%02hd - '%s')", s.c_str(), minOffs/MinsPerHour, abs(minOffs)%MinsPerHour, z.c_str()));
107   // - convert to output
108   if (!TzConvertTimestamp(intime,incontext,outcontext,&zones)) {
109     CONSOLEPRINTF(("input zone cannot be converted to output zone"));
110     return EXIT_FAILURE;
111   }
112   else {
113     // - input
114     TimestampToISO8601Str(s, intime, outcontext, true, true);
115     TimeZoneContextToName(outcontext, z, &zones);
116     TzResolveToOffset(outcontext, minOffs, intime, false, &zones);
117     CONSOLEPRINTF(("Output : %-25s (%+03hd:%02hd - '%s')", s.c_str(), minOffs/MinsPerHour, abs(minOffs)%MinsPerHour, z.c_str()));
118   }
119   return EXIT_SUCCESS;
120 } // timeConv
121
122 #endif // SYSYNC_TOOL
123
124
125
126
127 #ifndef PLATFORM_LROUND
128 // use generic implementation of lround
129 static sInt32 lround(double x) {
130   sInt32 l;
131   l=(sInt32)(x+0.5);
132   return l;
133 }
134 #endif
135
136 #ifndef PLATFORM_TRUNC
137 // use generic implementation of trunc
138 static double trunc(double x) {
139   sInt64 ll;
140   ll=(sInt64)(x);
141   return (double)ll;
142 }
143 #endif
144
145
146 #ifndef PLATFORM_DATE2LINEARDATE
147
148 // helper: Returns the biggest integer smaller than x
149 static sInt32 lfloor(double x) {
150   #if ( defined __MACH__ && defined __GNUC__ ) || defined _MSC_VER // XCode or Visual Studio
151     if (x<0) x= x-1;
152     return lround( x-0.5 );
153   #else
154     return (sInt32)floor( x );
155   #endif
156 } // lfloor
157
158 // convert date to linear date (generic version using our internal scale)
159 /* procedure calcEphTime(year:integer;month,day:byte;hour:single;var julDat:double);
160                 { Berechnet Julianisches Datum aus Weltzeit } */
161 lineardate_t date2lineardate(sInt16 aYear, sInt16 aMonth, sInt16 aDay)
162 {
163   // use custom algorithm that goes back to year -4712...
164         
165         /* const MinYear= -4712; */
166         const sInt32 MinYear = -4712;
167
168         /* var a,b:integer; */
169         sInt32 a,b;
170
171   /* if aMonth<3 then begin year:=year-1; aMonth:=aMonth+12; end; */
172   if (aMonth<3) { aYear--; aMonth+=12; }
173   /* if (aYear<1582) or
174     ((aYear=1582) and (aMonth<10)) or
175     ((aYear=1582) and (aMonth=10) and (aDay<15)) */
176   if (
177         aYear<1582 ||
178     (aYear==1582 && aMonth<10) ||
179     (aYear==1582 && aMonth==10 && aDay<15)
180   ) {
181         // julian
182         /* then b:=0    { julianisch } */
183         b=0;
184   }
185   else {
186         // gregorian
187     /* else begin a:=floor(aYear/100); b:=2-a+floor(a/4) end;    { gregorianisch } */
188         a=lfloor(aYear/100);
189         b=2-a+lfloor(a/4);
190   }
191   // now calc julian date
192   /*JulDat:=floor(365.25*(aYear-minYear)+1E-6)+round(30.6*(aMonth-3))+aDay+b+58.5;
193     JulDat:=JulDat+hour/24; */
194   return(
195     (lfloor(365.25*(aYear-MinYear)+1E-6)+lround(30.6*(aMonth-3))+aDay+b+59)
196     - linearDateOriginOffset // apply offset used for this target platform
197   );
198 } // date2lineardate
199
200 #endif // PLATFORM_DATE2LINEARDATE
201
202
203 // convert date to linear time
204 lineartime_t date2lineartime(sInt16 aYear, sInt16 aMonth, sInt16 aDay)
205 {
206   return date2lineardate(aYear,aMonth,aDay) * linearDateToTimeFactor;
207 } // date2lineartime
208
209
210 // convert time to linear time
211 lineartime_t time2lineartime(sInt16 aHour, sInt16 aMinute, sInt16 aSecond, sInt16 aMS)
212 {
213   lineartime_t ti =
214     ((((lineartime_t)aHour)*60 +
215       (lineartime_t)aMinute)*60 +
216      (lineartime_t)aSecond)*secondToLinearTimeFactor;
217   if (secondToLinearTimeFactor==1000)
218     ti+=aMS;
219   return ti;
220 } // time2lineartime
221
222
223 // convert lineardate to weekday
224 // 0=sunday, 1=monday ... 6=saturday
225 sInt16 lineardate2weekday(lineardate_t aLinearDate)
226 {
227   return (aLinearDate+linearDateOriginWeekday) % 7;
228 } // lineardate2weekday
229
230
231 // convert lineartime to weekday
232 // 0=sunday, 1=monday ... 6=saturday
233 sInt16 lineartime2weekday(lineartime_t aLinearTime)
234 {
235   // juldat seems to be sunday-based :-)
236   return lineardate2weekday(aLinearTime / linearDateToTimeFactor);
237 } // lineardate2weekday
238
239
240 // get number of days in a month
241 sInt16 getMonthDays(lineardate_t aLinearDate)
242 {
243   sInt16 y,m,d;
244   lineardate_t ld;
245
246   // get year and month of given date
247   lineardate2date(aLinearDate,&y,&m,&d);
248   // get first of this month
249   ld = date2lineardate(y,m,1);
250   // calculate next month
251   m++;
252   if (m>12) { m=1; y++; }
253   // return difference between 1st of current and 1st of next month = number of days in month
254   return date2lineardate(y,m,1) - ld;
255 } // getMonthDays
256
257
258
259 #ifndef PLATFORM_LINEARDATE2DATE
260
261 // convert lineardate to year/month/day
262 /*
263 procedure calcDat(zeitZone,julDat:double;var year:integer;var month,day,hour,min:byte;var sec:single);
264 { Berechnet das Kalenderdatum und Weltzeit aus Julianischem Datum }
265 */
266 void lineardate2date(lineardate_t aLinearDate,sInt16 *aYearP, sInt16 *aMonthP, sInt16 *aDayP)
267 {
268   // custom algorithm
269
270   /*
271   var JD0,JD,C,E:double;
272       B,D,F:integer;
273       hh:single;
274   */
275   double C,E;
276   sInt32 B,D,F;
277
278   // apply offset correction
279   aLinearDate+=linearDateOriginOffset;
280
281   // no time, no "correction" for date change at noon
282   /* JD:=julDat+zeitZone/24;
283      JD0:=sInt32(Jd+0.5); */
284   /*
285   if JD0<2299161 then begin
286     B:=0;
287     C:=JD0+1524;
288   end
289   else begin
290     B:=trunc((JD0-1867216.25)/36524.25);
291     C:=Jd0+(B-trunc(B/4))+1525.0;
292   end;
293   */
294   if (aLinearDate<2299161) {
295     B=0;
296     C=aLinearDate+1524;
297   }
298   else {
299     B=(sInt32)(trunc((aLinearDate-1867216.25)/36524.25));
300     C=aLinearDate+(B-trunc((double)B/4))+1525.0;
301   }
302   /*
303   D:=trunc((C-122.1)/365.25);
304   E:=365.0*D+trunc(D/4);
305   F:=trunc((C-E)/30.6001);
306   day:=trunc(C-E+0.5)-trunc(30.6001*F);
307   month:=F-1-12*trunc(F/14);
308   year:=D-4715-trunc((7+month)/10);
309   */
310   D=(sInt32)(trunc((C-122.1)/365.25));
311   E=365.0*D+trunc((double)D/4);
312   F=(sInt32)(trunc((C-E)/30.6001));
313   // return date
314   sInt16 month = (sInt16)(F-1-12*trunc((double)F/14));
315   if (aDayP)   *aDayP=(sInt16)(trunc(C-E+0.5)-trunc(30.6001*F));
316   if (aMonthP) *aMonthP=month;
317   if (aYearP)  *aYearP=(sInt16)(D-4715-trunc((double)(7+month)/10.0));
318   // no time
319   /*
320   hh:=24*(JD+0.5-JD0);
321   hour:=trunc(hh);
322   hh:=(hh-hour)*60;
323   min:=trunc(hh);
324   hh:=(hh-min)*60;
325   sec:=trunc(hh);
326   */
327 } // lineardate2date
328
329 #endif // PLATFORM_LINEARDATE2DATE
330
331
332 // convert lineartime to year/month/day
333 void lineartime2date(lineartime_t aLinearTime, sInt16 *aYearP, sInt16 *aMonthP, sInt16 *aDayP)
334 {
335   lineardate2date(lineartime2dateonly(aLinearTime), aYearP, aMonthP, aDayP);
336 } // lineartime2date
337
338
339 // convert lineartime to h,m,s,ms
340 void lineartime2time(lineartime_t aLinearTime, sInt16 *aHourP, sInt16 *aMinP, sInt16 *aSecP, sInt16 *aMSP)
341 {
342         if (aLinearTime<0) {
343         // negative time, create wrap around to make sure time remains positive
344     aLinearTime = lineartime2timeonly(aLinearTime);
345   }
346   if (secondToLinearTimeFactor==1) {
347     // no sub-seconds
348     if (aMSP) *aMSP = 0;
349   }
350   else {
351     // we have sub-seconds
352     if (aMSP) *aMSP = aLinearTime % secondToLinearTimeFactor;
353     aLinearTime /= secondToLinearTimeFactor;
354   }
355   if (aSecP) *aSecP = aLinearTime % 60;
356   aLinearTime /= 60;
357   if (aMinP) *aMinP = aLinearTime % 60;
358   aLinearTime /= 60;
359   if (aHourP) *aHourP = aLinearTime % 24; // to make sure we don't convert date part
360 } // lineartime2time
361
362
363 // convert seconds to linear time
364 lineartime_t seconds2lineartime(sInt32 aSeconds)
365 {
366   return aSeconds*secondToLinearTimeFactor;
367 } // seconds2lineartime
368
369
370 // convert linear time to seconds
371 sInt32 lineartime2seconds(lineartime_t aLinearTime)
372 {
373   return aLinearTime/secondToLinearTimeFactor;
374 } // lineartime2seconds
375
376
377 // get time-only part of a linear time
378 lineartime_t lineartime2timeonly(lineartime_t aLinearTime)
379 {
380   //return aLinearTime % linearDateToTimeFactor;
381   return aLinearTime-lineartime2dateonlyTime(aLinearTime);
382 } // lineartime2timeonly
383
384
385 // get date-only part of a linear time
386 lineardate_t lineartime2dateonly(lineartime_t aLinearTime)
387 {
388   return aLinearTime/linearDateToTimeFactor - (aLinearTime<0 ? 1 : 0);
389 } // lineartime2dateonly
390
391
392 // get date-only part of a linear time, in lineartime_t units
393 lineartime_t lineartime2dateonlyTime(lineartime_t aLinearTime)
394 {
395   lineartime_t ts = lineartime2dateonly(aLinearTime);
396   ts *= linearDateToTimeFactor;
397   return ts;
398 } // lineartime2dateonlyTime
399
400
401 } // namespace sysync
402
403 /* eof */