PLplot  5.10.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
qsastime_extra.c
Go to the documentation of this file.
1 //
2 // This software originally contributed under the LGPL in January 2009 to
3 // PLplot by the
4 // Cluster Science Centre
5 // QSAS team,
6 // Imperial College, London
7 // Copyright (C) 2009 Imperial College, London
8 //
9 // This file is part of PLplot.
10 //
11 // PLplot is free software; you can redistribute it and/or modify
12 // it under the terms of the GNU Library General Public License as published
13 // by the Free Software Foundation; either version 2 of the License, or
14 // (at your option) any later version.
15 //
16 // PLplot is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU Library General Public License for more details.
20 //
21 // You should have received a copy of the GNU Library General Public License
22 // along with PLplot; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 //
25 //
26 
27 // MJD measures from the start of 17 Nov 1858
28 
29 // These utilities use the Gregorian calendar after 4 Oct 1582 (Julian) i.e. from 15 Oct 1582 Gregoriam
30 // Note C libraries use Gregorian only from 14 Sept 1752
31 // More detailed discussion can be found at http://aa.usno.navy.mil/data/docs/JulianDate.php
32 // These routines have been compared with the results of the US Naval Observatory online converter.
33 // Modified Julian Date (MJD) = Julian Date (JD) - 2400000.5
34 //
35 // In all routines, specifying a day, hour, minute or second field greater than would be valid is
36 // handled with modulo arithmetic and safe.
37 // Thus 2006-12-32 00:62:00.0 will safely, and correctly, be treated as 2007-01-01 01:02:00.0
38 //
39 //
40 
41 #include "qsastime_extra.h"
42 
43 static double MJDtoJD = 2400000.5;
44 static double SecInDay = 86400; // we ignore leap seconds
45 
46 int setFromISOstring( const char* ISOstring, MJDtime *MJD, int forceJulian )
47 {
48  double seconds;
49  int y, m, d, h, min;
50  int startAt = 0;
51  int len = strlen( ISOstring );
52 
53  // ISO is "1995-01-23 02:33:17.235" or "1995-01-23T02:33:17.235Z"
54 
55  // parse off year
56 
57  y = strtol( &( ISOstring[startAt] ), NULL, 10 );
58  if ( ISOstring[startAt] == '-' || ISOstring[startAt] == '+' )
59  startAt++;
60  startAt += 5;
61  if ( startAt > len )
62  return 1;
63 
64  m = strtol( &( ISOstring[startAt] ), NULL, 10 );
65  startAt += 3;
66  if ( startAt > len )
67  return 1;
68 
69  d = strtol( &( ISOstring[startAt] ), NULL, 10 );
70  startAt += 3;
71  if ( startAt > len )
72  return 1;
73 
74  h = strtol( &( ISOstring[startAt] ), NULL, 10 );
75  startAt += 3;
76  if ( startAt > len )
77  return 1;
78 
79  min = strtol( &( ISOstring[startAt] ), NULL, 10 );
80  startAt += 3;
81  if ( startAt > len )
82  return 1;
83 
84  seconds = strtod( &( ISOstring[startAt] ), NULL );
85  setFromUT( y, m - 1, d, h, min, seconds, MJD, forceJulian );
86 
87  return 0;
88 }
89 
90 
91 void setFromDOY( int year, int doy, int hour, int min, double sec, MJDtime *MJD, int forceJulian )
92 {
93  // Set from Day Of Year format
94 
95  // convert Gregorian date plus time to MJD
96  // MJD measures from the start of 17 Nov 1858
97 
98  // the int flag forceJulian forces use of Julian calendar whatever the year
99  // default is to use Gregorian after 4 Oct 1582 (Julian) i.e. from 15 Oct 1582 Gregorian
100  // Note C libraries use Gregorian only from 14 Sept 1752 onwards
101 
102  int leaps, lastyear, extraDays;
103 
104  // N.B. There were known problems (both for the Julian and Gregorian
105  // cases) with the following leap year logic that were completely fixed
106  // in qsastime.c, but I (AWI) am not going to bother with these fixups
107  // here since this code only used for a specific test routine for limited
108  // date range and not for anything general.
109  if ( forceJulian && year <= 0 )
110  {
111  // count leap years on Julian Calendar
112  // MJD for Jan 1 0000 (correctly Jan 01, BCE 1) is - 678943, count from there
113  // negative CE (AD) years convert to BCE (BC) as BCE = 1 - CE, e.g. 2 BCE = -1 CE
114 
115  leaps = ( year - 4 ) / 4; // (note leaps is negative here and year 0 (1 BCE) was a leap year
116  MJD->base_day = year * 365 + leaps + doy - 678943;
117  }
118  else if ( forceJulian )
119  {
120  // count leap years on Julian Calendar
121  // MJD for Jan 1 0000 (correctly Jan 01, BCE 1) is - 678943, count from there
122 
123  leaps = ( year - 1 ) / 4;
124  MJD->base_day = year * 365 + leaps + doy - 678943;
125  }
126  else
127  {
128  // count leap years Gregorian Calendar - modern dates
129  // Algorithm below for 17 Nov 1858 (0 MJD) gives
130  // leaps = 450 and hence base_day of 678941, so subtract it to give MJD day
131 
132  lastyear = year - 1;
133  leaps = lastyear / 4 - lastyear / 100 + lastyear / 400;
134  MJD->base_day = year * 365 + leaps + doy - 678941;
135  }
136 
137  MJD->time_sec = sec + ( (double) min + (double) hour * 60. ) * 60.;
138 
139  if ( MJD->time_sec >= SecInDay )
140  {
141  extraDays = (int) ( MJD->time_sec / SecInDay );
142  MJD->base_day += extraDays;
143  MJD->time_sec -= extraDays * SecInDay;
144  }
145 
146  return;
147 }
148 
149 
150 void setFromBCE( int yearBCE, int month, int day, int hour, int min, double sec, MJDtime *MJD, int forceJulian )
151 {
152  // utility to allow user to input dates BCE (BC)
153 
154  int year = 1 - yearBCE;
155  setFromUT( year, month, day, hour, min, sec, MJD, forceJulian );
156 }
157 
158 void setFromMJD( double ModifiedJulianDate, MJDtime *MJD )
159 {
160  // convert MJD double into MJD structure
161  MJD->base_day = (int) ModifiedJulianDate;
162  MJD->time_sec = ( ModifiedJulianDate - MJD->base_day ) * SecInDay;
163 }
164 
165 void setFromJD( double JulianDate, MJDtime *MJD )
166 {
167  // break JD double into MJD based structure
168  // Note Julian Day starts Noon, so convert to MJD first
169 
170  MJD->base_day = (int) ( JulianDate - MJDtoJD );
171  MJD->time_sec = ( JulianDate - MJDtoJD - (double) MJD->base_day ) * SecInDay;
172 }
173 
174 void setFromCDFepoch( double cdfepoch, MJDtime *MJD )
175 {
176  // convert cdf epoch double into MJD structure
177  // Note that cdfepoch is msec from 0 AD on the Gregorian calendar
178 
179  double seconds = cdfepoch * 0.001;
180 
181  MJD->base_day = (int) ( seconds / 86400.0 );
182  MJD->time_sec = seconds - MJD->base_day * SecInDay;
183  MJD->base_day -= 678941;
184 }
185 
186 double getCDFepoch( MJDtime *MJD )
187 {
188  // convert MJD structure into cdf epoch double
189  // Note that cdfepoch is msec from 0 AD on the Gregorian Calendar
190 
191  int days = MJD->base_day + 678941;
192  double seconds = days * SecInDay + MJD->time_sec;
193  return seconds * 1000.;
194 }
195 
196 double getMJD( MJDtime *MJD )
197 {
198  // Return MJD as a double
199  return (double) MJD->base_day + MJD->time_sec / SecInDay;
200 }
201 
202 double getJD( MJDtime *MJD )
203 {
204  // Return JD as a double
205  double JD = getMJD( MJD ) + MJDtoJD;
206  return JD;
207 }
208 
209 double getDiffDays( MJDtime *MJD1, MJDtime *MJD2 )
210 {
211  // Return difference MJD1 - MJD2 in days as a double
212  double diff = (double) ( MJD1->base_day - MJD2->base_day ) + ( MJD1->time_sec - MJD2->time_sec ) / SecInDay;
213  return diff;
214 }
215 
216 double getDiffSecs( MJDtime *MJD1, MJDtime *MJD2 )
217 {
218  // Return difference MJD1 - MJD2 in seconds as a double
219  double diff = (double) ( MJD1->base_day - MJD2->base_day ) * SecInDay + ( MJD1->time_sec - MJD2->time_sec );
220  return diff;
221 }
222 
223 const char * getISOString( MJDtime* MJD, int delim, int forceJulian )
224 {
225  // ISO time string for UTC
226  // uses default behaviour for Julian/Gregorian switch over
227  //**
228  // Warning getISOString is not thread safe
229  // as it writes to a static variable DateTime
230  //*
231 
232  static char DateTime[50];
233  int y, m, d, hour, min;
234  int sec1, ysign;
235  double sec;
236  int slen;
237  char * ptr;
238 
239  breakDownMJD( &y, &m, &d, &hour, &min, &sec, MJD, forceJulian );
240 
241  if ( y < 0 )
242  {
243  ysign = 1;
244  y = -y;
245  }
246  else
247  ysign = 0;
248 
249  sec1 = (int) sec / 10;
250  sec -= (double) sec1 * 10;
251 
252  if ( delim == 1 )
253  {
254  if ( ysign == 0 )
255  sprintf( DateTime, "%04d-%02d-%02dT%02d:%02d:%01d%-11.10f", y, m + 1, d, hour, min, sec1, sec );
256  else
257  sprintf( DateTime, "-%04d-%02d-%02dT%02d:%02d:%01d%-11.10f", y, m + 1, d, hour, min, sec1, sec );
258 
259  // remove trailing white space
260  while ( ( ptr = strrchr( &( DateTime[0] ), ' ' ) ) != NULL )
261  ptr[0] = '\0';
262  strcat( &( DateTime[0] ), "Z" );
263  }
264  else
265  {
266  if ( ysign == 0 )
267  sprintf( DateTime, "%04d-%02d-%02d %02d:%02d:%01d%-11.10f", y, m + 1, d, hour, min, sec1, sec );
268  else
269  sprintf( DateTime, "-%04d-%02d-%02d %02d:%02d:%01d%-11.10f", y, m + 1, d, hour, min, sec1, sec );
270 
271  // remove trailing white space
272  slen = strlen( DateTime ) - 1;
273  while ( DateTime[slen] == ' ' )
274  {
275  DateTime[slen] = '\0';
276  slen--;
277  }
278  }
279  return &( DateTime[0] );
280 }