Time handling: Difference between revisions

From SPEDAS Wiki
Jump to navigation Jump to search
No edit summary
 
(12 intermediate revisions by 2 users not shown)
Line 1: Line 1:
== Overview ==
== Overview ==


Times in SPEDAS are stored as [https://en.wikipedia.org/wiki/Unix_time unix times] : the count of seconds elapsed since January 1, 1970 UTC.  The count is represented as IEEE 754 64-bit [[https://en.wikipedia.org/wiki/Double-precision_floating-point_format|double precision]] floating point numbers.  No leap seconds are included.  For dates prior to 1970, negative values are accepted.  The floating point symbols NaN and Infinity are not accepted and reliable behavior of time processing routines is not guaranteed for these inputs.  This representation combines both date and time of day into a single number which can be converted into other formats using SPEDAS routines.
Times in SPEDAS are stored as [https://en.wikipedia.org/wiki/Unix_time unix times]: the count of seconds elapsed since January 1, 1970 UTC.  The count is represented as IEEE 754 64-bit [https://en.wikipedia.org/wiki/Double-precision_floating-point_format double precision] floating point numbers.  No leap seconds are included.  For dates prior to 1970, negative values are accepted.  The floating point symbols NaN and Infinity are not accepted and reliable behavior of time processing routines is not guaranteed for these inputs.  This representation combines both date and time of day into a single number which can be converted into other formats using SPEDAS routines.


== Time Operations and Conversions ==
== Time Operations and Conversions ==
Line 8: Line 8:


Convert an ASCII datetime into a SPEDAS time:
Convert an ASCII datetime into a SPEDAS time:
<source lang="IDL">
<pre style="border: 1px solid LightGray">
SPEDAS> spedas_time = time_double('2007-03-23/02:00:00')
SPEDAS> spedas_time = time_double('2007-03-23/02:00:00')
SPEDAS> print,spedas_time
SPEDAS> print,spedas_time
   1.1746152e+09
   1.1746152e+09
</source>
</pre>


Convert a SPEDAS time into an ASCII datetime:
Convert a SPEDAS time into an ASCII datetime:
{{{
<pre style="border: 1px solid LightGray">
SPEDAS> ascii_time = time_string(spedas_time)
SPEDAS> ascii_time = time_string(spedas_time)
SPEDAS> print,ascii_time
SPEDAS> print,ascii_time
2007-03-23/02:00:00
2007-03-23/02:00:00
}}}
</pre>


Convert a SPEDAS time or ASCII time into a parsed structure format:
Convert a SPEDAS time or ASCII time into a parsed structure format:
{{{
<pre style="border: 1px solid LightGray">
SPEDAS> struct_time = time_struct('2007-03-23/02:00:00')
SPEDAS> struct_time = time_struct('2007-03-23/02:00:00')
SPEDAS> help,/str,struct_time
SPEDAS> help,/str,struct_time
Line 40: Line 40:
   TZONE          INT              0
   TZONE          INT              0
   TDIFF          INT              0
   TDIFF          INT              0
}}}
</pre>


Convert a time struct into SPEDAS time or ASCII time
Convert a time struct into SPEDAS time or ASCII time


{{{
<pre style="border: 1px solid LightGray">
SPEDAS> spedas_time = time_double(struct_time)
SPEDAS> spedas_time = time_double(struct_time)
SPEDAS> ascii_time = time_string(struct_time)
SPEDAS> ascii_time = time_string(struct_time)
Line 51: Line 51:
SPEDAS> print,ascii_time
SPEDAS> print,ascii_time
2007-03-23/02:00:00
2007-03-23/02:00:00
}}}
</pre>


Convert to a custom ASCII format:
Convert to a custom ASCII format:
{{{
<pre style="border: 1px solid LightGray">
SPEDAS> ;  TFORMAT:  a format string such as:  "YYYY-MM-DD/hh:mm:ss.ff DOW TDIFF"
SPEDAS> ;  TFORMAT:  a format string such as:  "YYYY-MM-DD/hh:mm:ss.ff DOW TDIFF"
SPEDAS> ;              the following tokens are recognized:
SPEDAS> ;              the following tokens are recognized:
Line 68: Line 68:
SPEDAS> ;                    DOW  - 3 character Day of week
SPEDAS> ;                    DOW  - 3 character Day of week
SPEDAS> ;                    DOY  - 3 character Day of Year
SPEDAS> ;                    DOY  - 3 character Day of Year
SPEDAS> ;                    TDIFF - 5 character, hours different from UTC   (useful with LOCAL keyword)
SPEDAS> ;                    TDIFF - 5 character, hours different from UTC  
SPEDAS> ;
SPEDAS> ;
SPEDAS> print,time_string(time_double('2007-03-23'),tformat='yy-DOY hh|mm|ss.fff') ;accepts double or string or struct
SPEDAS> print,time_string(time_double('2007-03-23'),tformat='yy-DOY hh|mm|ss.fff') ;accepts double or string or struct
Line 74: Line 74:
SPEDAS> print,time_string('2007-03-23',tformat='yy-DOY hh|mm|ss.fff') ;accepts double or string or struct
SPEDAS> print,time_string('2007-03-23',tformat='yy-DOY hh|mm|ss.fff') ;accepts double or string or struct
07-082 00|00|00.000
07-082 00|00|00.000
}}}
</pre>
 
Convert from a custom ASCII format to SPEDAS time:
<pre style="border: 1px solid LightGray">
SPEDAS> ; tformat input syntax the same as double->string conversion, except DOW is not acceptable input format code.
SPEDAS> spedas_time = time_double('FEB|23|13(01.1:02:03)',tformat='MTH|DD|yy(ss.f:mm:hh)') ;weird time format
SPEDAS> print,time_string(spedas_time,prec=1) ;prec=1 adds 1/10th sec precision on output format
2013-02-23/03:02:01.1
</pre>
 
Set and get current timerange for plotting and analysis:
Set and get current timerange for plotting and analysis:
{{{
<pre style="border: 1px solid LightGray">
SPEDAS> timespan,'2007-03-23/02:00:00',2,/hour ;set time span
SPEDAS> timespan,'2007-03-23/02:00:00',2,/hour ;set time span
TIMESPAN(53): Time range set from 2007-03-23/02:00:00 to 2007-03-23/04:00:00
TIMESPAN(53): Time range set from 2007-03-23/02:00:00 to 2007-03-23/04:00:00
Line 83: Line 92:
SPEDAS> print,time_string(timerange()) ; get time span (ASCII time)
SPEDAS> print,time_string(timerange()) ; get time span (ASCII time)
2007-03-23/02:00:00 2007-03-23/04:00:00
2007-03-23/02:00:00 2007-03-23/04:00:00
}}}
</pre>


All time conversion routines accept arrays of arguments.  They are vectorized so time and space performance is very good.
All time conversion routines accept arrays of arguments.  They are vectorized so time and space performance is very good.
{{{
<pre style="border: 1px solid LightGray">
SPEDAS>  arr = ['2007-03-23','2007-03-24/01','2007-03-25/01:02:03.04'] ;array of times, partial time entries are acceptable
SPEDAS>  arr = ['2007-03-23','2007-03-24/01','2007-03-25/01:02:03.04'] ;array of times, partial time entries are acceptable
SPEDAS> print,time_double(arr)
SPEDAS> print,time_double(arr)
Line 94: Line 103:
SPEDAS> help,time_struct(arr)
SPEDAS> help,time_struct(arr)
<Expression>    STRUCT    = -> TIME_STRUCTR Array[3]
<Expression>    STRUCT    = -> TIME_STRUCTR Array[3]
}}}
</pre>


SPEDAS double precision times are a natural format for performing mathematical operations on times
SPEDAS double precision times are a natural format for performing mathematical operations on times
{{{
<pre style="border: 1px solid LightGray">
SPEDAS> time1 = time_double('2007-03-23/01:02:03.4')
SPEDAS> time1 = time_double('2007-03-23/01:02:03.4')
SPEDAS> time2 = time_double('2007-03-23/01:02:04.5')
SPEDAS> time2 = time_double('2007-03-23/01:02:04.5')
Line 105: Line 114:
SPEDAS> print,time_string(arr+60.*60.) ;shift times by 1 hour (3600 seconds)
SPEDAS> print,time_string(arr+60.*60.) ;shift times by 1 hour (3600 seconds)
2007-03-23/02:02:03 2007-03-23/02:02:04
2007-03-23/02:02:03 2007-03-23/02:02:04
}}}
</pre>
Time structures can also be a useful format for performing time arithmetic.
Time structures can also be a useful format for performing time arithmetic.<p>
[[BR]]Warning: Care must be taken using this method because some of the information in the struct is redundant (For example, date & doy) and it is possible to create invalid structures.  (For example, date=32)  For maximum efficiency, consistency checks are not performed on time structures before conversion, thus results from invalid structures are not well defined.
Warning: Care must be taken using this method because some of the information in the struct is redundant (For example, date & doy) and it is possible to create invalid structures.  (For example, date=32)  For maximum efficiency, consistency checks are not performed on time structures before conversion, thus results from invalid structures are not well defined.
{{{
<pre style="border: 1px solid LightGray">
SPEDAS> ts = time_struct('2007-03-23')
SPEDAS> ts = time_struct('2007-03-23')
SPEDAS> ts.date+=1
SPEDAS> ts.date+=1
Line 122: Line 131:
SPEDAS> print,time_string(time_double(ts)) ;produces correct result, unexpectedly
SPEDAS> print,time_string(time_double(ts)) ;produces correct result, unexpectedly
2007-04-01/00:00:00
2007-04-01/00:00:00
}}}
</pre>


== Precision ==
== Precision ==
Line 129: Line 138:


One year from the epoch, precision is ~7 ns.  For contemporary times, the precision is ~300 ns. Precision declines to ~7 us at 1000 years from the epoch.  
One year from the epoch, precision is ~7 ns.  For contemporary times, the precision is ~300 ns. Precision declines to ~7 us at 1000 years from the epoch.  
[[BR]][[BR]]
 
||= Precision at sample dates =||= Precision as a function of years from the epoch =||
{| border="1" cellspacing="0" cellpadding="5" align="center"
{{{#!td
|-
||= Year(Jan 1) =||= Precision(ns) =||
!Precision at sample dates
||970||7007||
!Precision as a function of years from the epoch
||1870||700.7||
|-
||1900||490.1||
|  
||1950||140.1||
{| border="1" cellspacing="0" cellpadding="5" align="center"
||1960||70.07||
!Year(Jan 1)
||1969||7.007||
!Precision(ns)
||1971||7.007||
|-
||1980||70.07||
|970||7007
||2007||259.3||
|-
||2013||301.1||
|1870||700.7
||2070||700.7||
|-
||2970||7007||
|1900||490.1
}}}
|-
{{{#!td
|1950||140.1
[[Image(spedas_time_precision.png, 600px)]]
|-
}}}
|1960||70.07
||
|-
[[BR]][[BR]]
|1969||7.007
|-
|1971||7.007
|-
|1980||70.07
|-
|2007||259.3
|-
|2013||301.1
|-
|2070||700.7
|-
|2970||7007
|}
[[File:spedas_time_precision.png|700px]]
|}


== TT2000 times ==
== TT2000 times ==
Line 157: Line 181:


time_double can also be used to convert directly from TT2000.
time_double can also be used to convert directly from TT2000.
{{{
<pre style="border: 1px solid LightGray">
SPEDAS> print,time_string(time_double(0LL,/tt2000)) ;'LL' IDL syntax indicates a 64 bit signed integer.
SPEDAS> print,time_string(time_double(0LL,/tt2000)) ;'LL' IDL syntax indicates a 64 bit signed integer.
2000-01-01/11:58:55 ;shouldn't convert to 12:00:00 because 64.1840 leap seconds have elapsed between the SPEDAS epoch and the J2000 epoch
2000-01-01/11:58:55 ;shouldn't convert to 12:00:00 because 64.1840 leap seconds have elapsed between the SPEDAS epoch and the J2000 epoch
}}}
</pre>

Latest revision as of 01:31, 11 February 2014

Overview

Times in SPEDAS are stored as unix times: the count of seconds elapsed since January 1, 1970 UTC. The count is represented as IEEE 754 64-bit double precision floating point numbers. No leap seconds are included. For dates prior to 1970, negative values are accepted. The floating point symbols NaN and Infinity are not accepted and reliable behavior of time processing routines is not guaranteed for these inputs. This representation combines both date and time of day into a single number which can be converted into other formats using SPEDAS routines.

Time Operations and Conversions

A set of routines are available in SPEDAS to perform common time operations. Some examples of common routines and operations follow.

Convert an ASCII datetime into a SPEDAS time:

SPEDAS> spedas_time = time_double('2007-03-23/02:00:00')
SPEDAS> print,spedas_time
   1.1746152e+09

Convert a SPEDAS time into an ASCII datetime:

SPEDAS> ascii_time = time_string(spedas_time)
SPEDAS> print,ascii_time
2007-03-23/02:00:00

Convert a SPEDAS time or ASCII time into a parsed structure format:

SPEDAS> struct_time = time_struct('2007-03-23/02:00:00')
SPEDAS> help,/str,struct_time
** Structure TIME_STRUCTR, 14 tags, length=48, data length=42:
   YEAR            INT           2007
   MONTH           INT              3
   DATE            INT             23
   HOUR            INT              2
   MIN             INT              0
   SEC             INT              0
   FSEC            DOUBLE           0.0000000
   DAYNUM          LONG            732757
   DOY             INT             82
   DOW             INT              4
   SOD             DOUBLE           7200.0000
   DST             INT              0
   TZONE           INT              0
   TDIFF           INT              0

Convert a time struct into SPEDAS time or ASCII time

SPEDAS> spedas_time = time_double(struct_time)
SPEDAS> ascii_time = time_string(struct_time)
SPEDAS> print,spedas_time
   1.1746152e+09
SPEDAS> print,ascii_time
2007-03-23/02:00:00

Convert to a custom ASCII format:

SPEDAS> ;  TFORMAT:   a format string such as:  "YYYY-MM-DD/hh:mm:ss.ff DOW TDIFF"
SPEDAS> ;               the following tokens are recognized:
SPEDAS> ;                    YYYY  - 4 digit year
SPEDAS> ;                    yy    - 2 digit year
SPEDAS> ;                    MM    - 2 digit month
SPEDAS> ;                    DD    - 2 digit date
SPEDAS> ;                    hh    - 2 digit hour
SPEDAS> ;                    mm    - 2 digit minute
SPEDAS> ;                    ss    - 2 digit seconds
SPEDAS> ;                    .fff   - fractional seconds
SPEDAS> ;                    MTH   - 3 character month
SPEDAS> ;                    DOW   - 3 character Day of week
SPEDAS> ;                    DOY   - 3 character Day of Year
SPEDAS> ;                    TDIFF - 5 character, hours different from UTC 
SPEDAS> ;
SPEDAS> print,time_string(time_double('2007-03-23'),tformat='yy-DOY hh|mm|ss.fff') ;accepts double or string or struct
07-082 00|00|00.000
SPEDAS> print,time_string('2007-03-23',tformat='yy-DOY hh|mm|ss.fff') ;accepts double or string or struct
07-082 00|00|00.000

Convert from a custom ASCII format to SPEDAS time:

SPEDAS> ; tformat input syntax the same as double->string conversion, except DOW is not acceptable input format code.
SPEDAS> spedas_time = time_double('FEB|23|13(01.1:02:03)',tformat='MTH|DD|yy(ss.f:mm:hh)') ;weird time format
SPEDAS> print,time_string(spedas_time,prec=1) ;prec=1 adds 1/10th sec precision on output format
2013-02-23/03:02:01.1

Set and get current timerange for plotting and analysis:

SPEDAS> timespan,'2007-03-23/02:00:00',2,/hour ;set time span
TIMESPAN(53): Time range set from 2007-03-23/02:00:00 to 2007-03-23/04:00:00
SPEDAS> print,timerange() ;get time span (spedas time)
   1.1746152e+09   1.1746224e+09
SPEDAS> print,time_string(timerange()) ; get time span (ASCII time)
2007-03-23/02:00:00 2007-03-23/04:00:00

All time conversion routines accept arrays of arguments. They are vectorized so time and space performance is very good.

SPEDAS>  arr = ['2007-03-23','2007-03-24/01','2007-03-25/01:02:03.04'] ;array of times, partial time entries are acceptable
SPEDAS> print,time_double(arr)
   1.1746080e+09   1.1746980e+09   1.1747845e+09
SPEDAS> print,time_string(arr)
2007-03-23/00:00:00 2007-03-24/01:00:00 2007-03-25/01:02:03
SPEDAS> help,time_struct(arr)
<Expression>    STRUCT    = -> TIME_STRUCTR Array[3]

SPEDAS double precision times are a natural format for performing mathematical operations on times

SPEDAS> time1 = time_double('2007-03-23/01:02:03.4')
SPEDAS> time2 = time_double('2007-03-23/01:02:04.5')
SPEDAS> print,time2-time1 ;difference between two times in seconds
       1.0999999
SPEDAS> arr = [time1,time2]
SPEDAS> print,time_string(arr+60.*60.) ;shift times by 1 hour (3600 seconds)
2007-03-23/02:02:03 2007-03-23/02:02:04

Time structures can also be a useful format for performing time arithmetic.

Warning: Care must be taken using this method because some of the information in the struct is redundant (For example, date & doy) and it is possible to create invalid structures. (For example, date=32) For maximum efficiency, consistency checks are not performed on time structures before conversion, thus results from invalid structures are not well defined.

SPEDAS> ts = time_struct('2007-03-23')
SPEDAS> ts.date+=1
SPEDAS> print,time_string(ts) ;produces expected result
2007-03-24/00:00:00
SPEDAS> ts = time_struct('2007-03-23')
SPEDAS> ts.doy+=1
SPEDAS>  print,time_string(ts) ;produces unexpected result
2007-03-23/00:00:00
SPEDAS> ts.date=32
SPEDAS> print,time_string(ts) ;produces incorrect result
2007-03-32/00:00:00
SPEDAS> print,time_string(time_double(ts)) ;produces correct result, unexpectedly
2007-04-01/00:00:00

Precision

Since the numbers are represented using floating point numbers, the actual precision of any SPEDAS time will vary with distance from the 1970 epoch. Precision represents the smallest separation between two SPEDAS times before arithmetic operations will treat them as equal. The average error for a random time represented as a SPEDAS time will be one half the precision at the represented time.

One year from the epoch, precision is ~7 ns. For contemporary times, the precision is ~300 ns. Precision declines to ~7 us at 1000 years from the epoch.

Precision at sample dates Precision as a function of years from the epoch
Year(Jan 1) Precision(ns)
970 7007
1870 700.7
1900 490.1
1950 140.1
1960 70.07
1969 7.007
1971 7.007
1980 70.07
2007 259.3
2013 301.1
2070 700.7
2970 7007

TT2000 times

SPEDAS has limited support for TT2000. SPEDAS can accept and convert TT2000 times, but there will be some loss of precision on conversion to floating point format because SPEDAS precision is worse than the 1ns of TT2000. Since TT2000 times include leap seconds, they will be removed upon conversion to the SPEDAS format so that dates in SPEDAS will be consistent, comparable, and interoperable. The cdf2tplot routine will automatically convert TT2000 times to SPEDAS times when importing CDFs if the SPDF CDF plugin for IDL is up to date.

time_double can also be used to convert directly from TT2000.

SPEDAS> print,time_string(time_double(0LL,/tt2000)) ;'LL' IDL syntax indicates a 64 bit signed integer.
2000-01-01/11:58:55 ;shouldn't convert to 12:00:00 because 64.1840 leap seconds have elapsed between the SPEDAS epoch and the J2000 epoch