PLplot 5.15.0
Loading...
Searching...
No Matches
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
43static double MJDtoJD = 2400000.5;
44static double SecInDay = 86400; // we ignore leap seconds
45
46int 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
91void 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
150void 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
158void 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
165void 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
174void 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
186double 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
196double getMJD( MJDtime *MJD )
197{
198 // Return MJD as a double
199 return (double) MJD->base_day + MJD->time_sec / SecInDay;
200}
201
202double getJD( MJDtime *MJD )
203{
204 // Return JD as a double
205 double JD = getMJD( MJD ) + MJDtoJD;
206 return JD;
207}
208
209double 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
216double 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
223const 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}
#define min(x, y)
Definition nnpi.c:87
int setFromUT(int year, int month, int day, int hour, int min, double sec, MJDtime *MJD, int forceJulian)
Definition qsastime.c:71
void breakDownMJD(int *year, int *month, int *day, int *hour, int *min, double *sec, const MJDtime *MJD, int forceJulian)
Definition qsastime.c:289
void setFromBCE(int yearBCE, int month, int day, int hour, int min, double sec, MJDtime *MJD, int forceJulian)
int setFromISOstring(const char *ISOstring, MJDtime *MJD, int forceJulian)
double getDiffDays(MJDtime *MJD1, MJDtime *MJD2)
double getMJD(MJDtime *MJD)
static double MJDtoJD
void setFromCDFepoch(double cdfepoch, MJDtime *MJD)
static double SecInDay
void setFromJD(double JulianDate, MJDtime *MJD)
void setFromDOY(int year, int doy, int hour, int min, double sec, MJDtime *MJD, int forceJulian)
double getDiffSecs(MJDtime *MJD1, MJDtime *MJD2)
double getJD(MJDtime *MJD)
void setFromMJD(double ModifiedJulianDate, MJDtime *MJD)
double getCDFepoch(MJDtime *MJD)
const char * getISOString(MJDtime *MJD, int delim, int forceJulian)