LSST Applications  21.0.0-172-gfb10e10a+18fedfabac,22.0.0+297cba6710,22.0.0+80564b0ff1,22.0.0+8d77f4f51a,22.0.0+a28f4c53b1,22.0.0+dcf3732eb2,22.0.1-1-g7d6de66+2a20fdde0d,22.0.1-1-g8e32f31+297cba6710,22.0.1-1-geca5380+7fa3b7d9b6,22.0.1-12-g44dc1dc+2a20fdde0d,22.0.1-15-g6a90155+515f58c32b,22.0.1-16-g9282f48+790f5f2caa,22.0.1-2-g92698f7+dcf3732eb2,22.0.1-2-ga9b0f51+7fa3b7d9b6,22.0.1-2-gd1925c9+bf4f0e694f,22.0.1-24-g1ad7a390+a9625a72a8,22.0.1-25-g5bf6245+3ad8ecd50b,22.0.1-25-gb120d7b+8b5510f75f,22.0.1-27-g97737f7+2a20fdde0d,22.0.1-32-gf62ce7b1+aa4237961e,22.0.1-4-g0b3f228+2a20fdde0d,22.0.1-4-g243d05b+871c1b8305,22.0.1-4-g3a563be+32dcf1063f,22.0.1-4-g44f2e3d+9e4ab0f4fa,22.0.1-42-gca6935d93+ba5e5ca3eb,22.0.1-5-g15c806e+85460ae5f3,22.0.1-5-g58711c4+611d128589,22.0.1-5-g75bb458+99c117b92f,22.0.1-6-g1c63a23+7fa3b7d9b6,22.0.1-6-g50866e6+84ff5a128b,22.0.1-6-g8d3140d+720564cf76,22.0.1-6-gd805d02+cc5644f571,22.0.1-8-ge5750ce+85460ae5f3,master-g6e05de7fdc+babf819c66,master-g99da0e417a+8d77f4f51a,w.2021.48
LSST Data Management Base Package
Public Types | Public Member Functions | Static Public Member Functions | Static Public Attributes | Friends | List of all members
lsst::daf::base::DateTime Class Reference

Class for handling dates/times, including MJD, UTC, and TAI. More...

#include <DateTime.h>

Public Types

enum  DateSystem { JD = 0 , MJD , EPOCH }
 
enum  Timescale { TAI = 5 , UTC , TT }
 

Public Member Functions

 DateTime ()
 Default constructor: construct an invalid DateTime. More...
 
 DateTime (long long nsecs, Timescale scale=TAI)
 Construct a DateTime from nanoseconds since the unix epoch. More...
 
 DateTime (double date, DateSystem system=MJD, Timescale scale=TAI)
 Construct a DateTime from a double in the specified system and scale. More...
 
 DateTime (int year, int month, int day, int hr, int min, int sec, Timescale scale=TAI)
 Construct a DateTime from year, month, day, etc. More...
 
 DateTime (std::string const &iso8601, Timescale scale)
 Construct a DateTime from an ISO8601 string. More...
 
long long nsecs (Timescale scale=TAI) const
 Get date as nanoseconds since the unix epoch. More...
 
double get (DateSystem system=MJD, Timescale scale=TAI) const
 Get date as a double in a specified representation, such as MJD. More...
 
std::string toString (Timescale scale) const
 Get date as an ISO8601-formatted string. More...
 
struct tm gmtime (Timescale scale) const
 Get date as a tm struct, with truncated fractional seconds. More...
 
struct timespec timespec (Timescale scale) const
 Get date as a timespec struct, with time in seconds and nanoseconds. More...
 
struct timeval timeval (Timescale scale) const
 Get date as a timeval struct, with time in seconds and microseconds. More...
 
bool isValid () const
 Is this date valid? More...
 
bool operator== (DateTime const &rhs) const
 
std::size_t hash_value () const noexcept
 Return a hash of this object. More...
 

Static Public Member Functions

static DateTime now (void)
 Return current time as a DateTime. More...
 
static void initializeLeapSeconds (std::string const &leapString)
 Initialize the leap second table from USNO. More...
 

Static Public Attributes

constexpr static long long invalid_nsecs = std::numeric_limits<std::int64_t>::min()
 

Friends

class boost::serialization::access
 

Detailed Description

Class for handling dates/times, including MJD, UTC, and TAI.

Definition at line 64 of file DateTime.h.

Member Enumeration Documentation

◆ DateSystem

Enumerator
JD 
MJD 
EPOCH 

Definition at line 66 of file DateTime.h.

66 { JD = 0, MJD, EPOCH }; // EPOCH is Julian epoch year

◆ Timescale

Enumerator
TAI 
UTC 
TT 

Definition at line 68 of file DateTime.h.

68  {
69  TAI = 5,
70  UTC,
71  TT
72  }; // use values that do not overlap DateSystem

Constructor & Destructor Documentation

◆ DateTime() [1/5]

lsst::daf::base::DateTime::DateTime ( )
explicit

Default constructor: construct an invalid DateTime.

Definition at line 307 of file DateTime.cc.

307 : _nsecs(DateTime::invalid_nsecs) {}
constexpr static long long invalid_nsecs
Definition: DateTime.h:75

◆ DateTime() [2/5]

lsst::daf::base::DateTime::DateTime ( long long  nsecs,
Timescale  scale = TAI 
)
explicit

Construct a DateTime from nanoseconds since the unix epoch.

Parameters
[in]nsecsinteger nanoseconds since the unix epoch; if nsecs == DateTime.invalid_nsecs then the DateTime is invalid, regardless of scale
[in]scaletime scale of input (TAI, TT or UTC, default TAI).
Exceptions
lsst.pex.exceptions.DomainErrorif scale is UTC and the date is before 1961-01-01

Definition at line 309 of file DateTime.cc.

309 : _nsecs(nsecAnyToTai(nsecs, scale)) {}
long long nsecs(Timescale scale=TAI) const
Get date as nanoseconds since the unix epoch.
Definition: DateTime.cc:448
def scale(algorithm, min, max=None, frame=None)
Definition: ds9.py:108

◆ DateTime() [3/5]

lsst::daf::base::DateTime::DateTime ( double  date,
DateSystem  system = MJD,
Timescale  scale = TAI 
)
explicit

Construct a DateTime from a double in the specified system and scale.

Parameters
[in]datespecified date
[in]systemtime system of input (JD, MJD, or [Julian] EPOCH)
[in]scaletime scale of input (TAI, TT or UTC, default TAI).
Exceptions
lsst.pex.exceptions.DomainErrorif scale is UTC and the date is before 1961-01-01

Definition at line 311 of file DateTime.cc.

311  {
312  switch (system) {
313  case MJD:
314  setNsecsFromMjd(date, scale);
315  break;
316  case JD:
317  setNsecsFromJd(date, scale);
318  break;
319  case EPOCH:
320  setNsecsFromEpoch(date, scale);
321  break;
322  default:
323  throw LSST_EXCEPT(pexEx::InvalidParameterError, "DateSystem must be MJD, JD, or EPOCH");
324  break;
325  }
326 }
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Definition: Exception.h:48
Reports invalid arguments.
Definition: Runtime.h:66

◆ DateTime() [4/5]

lsst::daf::base::DateTime::DateTime ( int  year,
int  month,
int  day,
int  hr,
int  min,
int  sec,
Timescale  scale = TAI 
)

Construct a DateTime from year, month, day, etc.

(tm struct fields)

Parameters
[in]yearyear; must be in the range [1902, 2261], inclusive.
[in]monthmonth number, where January = 1
[in]dayday of the month (1 to 31).
[in]hrhour (0 to 23)
[in]minminute (0 to 59)
[in]secinteger seconds (0 to 60)
[in]scaletime scale of input (TAI, TT or UTC, default TAI).
Exceptions
lsst.pex.exceptions.DomainErrorif year is < 1902 or > 2261, or if scale is UTC and the date is before 1961-01-01 (the start of the leap second table)

Definition at line 328 of file DateTime.cc.

328  {
329  int const minYear = 1902;
330  int const maxYear = 2261;
331  if ((year < minYear) || (year > maxYear)) {
332  throw LSST_EXCEPT(
334  (boost::format("Year = %d out of range [%04d, %04d]") % year % minYear % maxYear).str());
335  }
336 
337  struct tm tm;
338  tm.tm_year = year - 1900;
339  tm.tm_mon = month - 1;
340  tm.tm_mday = day;
341  tm.tm_hour = hr;
342  tm.tm_min = min;
343  tm.tm_sec = sec;
344  tm.tm_wday = 0;
345  tm.tm_yday = 0;
346  tm.tm_isdst = 0;
347  tm.tm_gmtoff = 0;
348 
349  // Convert to seconds since the epoch, correcting to UTC.
350  // Although timegm() is non-standard, it is a commonly-supported
351  // extension and is much safer/more reliable than mktime(3) in that
352  // it doesn't try to deal with the anomalies of local time zones.
353  time_t secs = timegm(&tm);
354 
355  // long long nsecs will blow out beyond 1677-09-21T00:00:00 and 2262-04-12T00:00:00
356  // (refering to the values of EPOCH_IN_MJD +/- MAX_DAYS ... exceeds 64 bits.)
357  // On older machines a tm struct is only 32 bits, and saturates at:
358  // low end - 1901-12-13, 20:45:52
359  // hi end - 2038-01-19, 03:14:07
360  // On newer machines the upper limit is a date in 2262, but the low end is unchanged,
361  // and a unit test will show the problem for dates later than 2038-01-19
362 
363  // timegm returns -1 on error, but the date at unix epoch -1 second also returns a valid value of -1,
364  // so be sure to test for that
365 
366  if (secs == -1) {
367  bool isBad = true; // assume the worst
368  if (year == 1969) {
369  // date may be the one date at which unix sec = -1; try a different year
370  tm.tm_year = 70;
371  if (timegm(&tm) != -1) {
372  isBad = false;
373  }
374  }
375  if (isBad) {
377  (boost::format("Unconvertible date: %04d-%02d-%02dT%02d:%02d:%02d") % year %
378  month % day % hr % min % sec)
379  .str());
380  }
381  }
382 
383  _nsecs = nsecAnyToTai(secs * LL_NSEC_PER_SEC, scale);
384 }
int min
Reports arguments outside the domain of an operation.
Definition: Runtime.h:57
def format(config, name=None, writeSourceLine=True, prefix="", verbose=False)
Definition: history.py:174

◆ DateTime() [5/5]

lsst::daf::base::DateTime::DateTime ( std::string const &  iso8601,
Timescale  scale 
)
explicit

Construct a DateTime from an ISO8601 string.

Accepts a restricted subset of ISO8601: yyyy-mm-ddThh:mm:ss.nnnnnnnnnZ where:

  • the final Z is required for UTC and prohibited for TAI or TT
  • the - and : separators are optional
  • the decimal point and fractional seconds are optional
  • the decimal point may be a comma
Parameters
[in]iso8601ISO8601 string representation of date and time
[in]scaletime scale of input (TAI, TT or UTC, default TAI).
Exceptions
lsst.pex.exceptions.DomainErrorif year is < 1902 or > 2261, or if scale is UTC and the date is before 1961-01-01 (the start of the leap second table)

Definition at line 386 of file DateTime.cc.

386  {
387  std::regex re;
388  if (scale == UTC) {
389  // time zone "Z" required
390  re = std::regex(
391  "(\\d{4})-?(\\d{2})-?(\\d{2})"
392  "T"
393  "(\\d{2}):?(\\d{2}):?(\\d{2})"
394  "([.,](\\d*))?"
395  "Z");
396  } else {
397  // no time zone character accepted
398  re = std::regex(
399  "(\\d{4})-?(\\d{2})-?(\\d{2})"
400  "T"
401  "(\\d{2}):?(\\d{2}):?(\\d{2})"
402  "([.,](\\d*))?");
403  }
404  std::smatch matches;
405  if (!regex_match(iso8601, matches, re)) {
406  throw LSST_EXCEPT(lsst::pex::exceptions::DomainError, "Not in acceptable ISO8601 format: " + iso8601);
407  }
408  // determine TAI nsec truncated to integer seconds
409  // by constructing a DateTime from year, month, day...
410  DateTime dt(atoi(matches.str(1).c_str()), atoi(matches.str(2).c_str()), atoi(matches.str(3).c_str()),
411  atoi(matches.str(4).c_str()), atoi(matches.str(5).c_str()), atoi(matches.str(6).c_str()),
412  scale);
413  _nsecs = dt._nsecs;
414  // add fractional seconds, if any
415  if (matches[7].matched) {
416  std::string frac = matches.str(8);
417  int places = frac.size();
418  if (places > 9) { // truncate fractional nanosec
419  frac.erase(9);
420  }
421  int value = atoi(frac.c_str());
422  while (places < 9) {
423  value *= 10;
424  ++places;
425  }
426  _nsecs += value;
427  }
428 }
T atoi(T... args)
T c_str(T... args)
DateTime()
Default constructor: construct an invalid DateTime.
Definition: DateTime.cc:307
T erase(T... args)
T regex_match(T... args)
T size(T... args)
T str(T... args)

Member Function Documentation

◆ get()

double lsst::daf::base::DateTime::get ( DateSystem  system = MJD,
Timescale  scale = TAI 
) const

Get date as a double in a specified representation, such as MJD.

Returns
the date in the required system, for the requested scale
Parameters
[in]systemdesired time system (JD, MJD, or [Julian] EPOCH)
[in]scaledesired time scale (TAI, TT or UTC)
Exceptions
lsst.pex.exceptions.DomainErrorif scale is UTC and the UTC date is before 1961-01-01
lsst.pex.exceptions.RuntimeErrorif DateTime is invalid

Definition at line 430 of file DateTime.cc.

430  {
431  _assertValid();
432  switch (system) {
433  case MJD:
434  return _getMjd(scale);
435  break;
436  case JD:
437  return _getJd(scale);
438  break;
439  case EPOCH:
440  return _getEpoch(scale);
441  break;
442  default:
443  throw LSST_EXCEPT(pexEx::InvalidParameterError, "DateSystem must be MJD, JD, or EPOCH");
444  break;
445  }
446 }

◆ gmtime()

struct tm lsst::daf::base::DateTime::gmtime ( Timescale  scale) const

Get date as a tm struct, with truncated fractional seconds.

Parameters
[in]scaledesired time scale (TAI, TT or UTC)
Returns
date as a tm struct
Exceptions
lsst.pex.exceptions.DomainErrorif scale is UTC and the UTC date is before 1961-01-01
lsst.pex.exceptions.RuntimeErrorif DateTime is invalid

Definition at line 464 of file DateTime.cc.

466  {
467  _assertValid();
468  struct tm gmt;
469  long long nsecs = nsecTaiToAny(_nsecs, scale);
470  // Round to negative infinity
471  long long frac = nsecs % LL_NSEC_PER_SEC;
472  if (nsecs < 0 && frac < 0) {
473  nsecs -= LL_NSEC_PER_SEC + frac;
474  } else {
475  nsecs -= frac;
476  }
477  time_t secs = static_cast<time_t>(nsecs / LL_NSEC_PER_SEC);
478  gmtime_r(&secs, &gmt);
479  return gmt;
480 }

◆ hash_value()

std::size_t lsst::daf::base::DateTime::hash_value ( ) const
noexcept

Return a hash of this object.

Definition at line 516 of file DateTime.cc.

516 { return std::hash<long long>()(_nsecs); }

◆ initializeLeapSeconds()

void lsst::daf::base::DateTime::initializeLeapSeconds ( std::string const &  leapString)
static

Initialize the leap second table from USNO.

The data can be found here: http://maia.usno.navy.mil/ser7/tai-utc.dat and is saved in DateTime.cc as static constant leapString.

Parameters
leapStringleap second table from USNO as a single multiline string.

Definition at line 528 of file DateTime.cc.

528  {
529  Leap l;
530  leapSecTable.clear();
531  std::regex re(
532  "\\d{4}.*?=JD\\s*([\\d.]+)\\s+TAI-UTC=\\s+([\\d.]+)\\s+S"
533  " \\+ \\(MJD - ([\\d.]+)\\) X ([\\d.]+)\\s*S");
534 
535 
536  for (std::sregex_iterator i = std::sregex_iterator(leapString.begin(), leapString.end(), re);
537  i != std::sregex_iterator(); ++i) {
538  double mjdUtc = std::stod((*i)[1]) - MJD_TO_JD;
539  l.offset = std::stod((*i)[2]);
540  l.mjdRef = std::stod((*i)[3]);
541  l.drift = std::stod((*i)[4]);
542  l.whenUtc = static_cast<long long>((mjdUtc - EPOCH_IN_MJD) * NSEC_PER_DAY);
543  l.whenTai = l.whenUtc + static_cast<long long>(1.0e9 * (l.offset + (mjdUtc - l.mjdRef) * l.drift));
544  leapSecTable.push_back(l);
545  }
546 }
T begin(T... args)
T end(T... args)
T stod(T... args)

◆ isValid()

bool lsst::daf::base::DateTime::isValid ( ) const
inline

Is this date valid?

Definition at line 203 of file DateTime.h.

203 { return _nsecs != DateTime::invalid_nsecs; };

◆ now()

DateTime lsst::daf::base::DateTime::now ( void  )
static

Return current time as a DateTime.

Assumes the system clock keeps UTC, as almost all computers do.

Definition at line 518 of file DateTime.cc.

518  {
519  struct timeval tv;
520  int ret = gettimeofday(&tv, 0);
521  if (ret != 0) {
522  throw LSST_EXCEPT(lsst::pex::exceptions::RuntimeError, "Unable to get current time");
523  }
524  long long nsecs = tv.tv_sec * LL_NSEC_PER_SEC + tv.tv_usec * 1000LL;
525  return DateTime(nsecs, DateTime::UTC);
526 }
struct timeval timeval(Timescale scale) const
Get date as a timeval struct, with time in seconds and microseconds.
Definition: DateTime.cc:491
Reports errors that are due to events beyond the control of the program.
Definition: Runtime.h:104

◆ nsecs()

long long lsst::daf::base::DateTime::nsecs ( Timescale  scale = TAI) const

Get date as nanoseconds since the unix epoch.

Note
If the DateTime is invalid then the returned value is DateTime.invalid_nsecs, regardless of scale.
Parameters
[in]scaledesired time scale (TAI, TT or UTC)
Returns
the date as nanoseconds since the unix epoch in the specified time scale
Exceptions
lsst.pex.exceptions.DomainErrorif scale is UTC and the UTC date is before 1961-01-01

Definition at line 448 of file DateTime.cc.

448  {
449  if (!isValid()) {
450  // return the same invalid value for all time scales
452  }
453  return nsecTaiToAny(_nsecs, scale);
454 }
bool isValid() const
Is this date valid?
Definition: DateTime.h:203

◆ operator==()

bool lsst::daf::base::DateTime::operator== ( DateTime const &  rhs) const

Definition at line 514 of file DateTime.cc.

514 { return _nsecs == rhs._nsecs; }

◆ timespec()

struct timespec lsst::daf::base::DateTime::timespec ( Timescale  scale) const

Get date as a timespec struct, with time in seconds and nanoseconds.

Parameters
[in]scaleDesired time scale (TAI, TT or UTC)
Returns
date as a timespec struct
Exceptions
lsst.pex.exceptions.DomainErrorif scale is UTC and the UTC date is before 1961-01-01
lsst.pex.exceptions.RuntimeErrorif DateTime is invalid

Definition at line 464 of file DateTime.cc.

482  {
483  _assertValid();
484  struct timespec ts;
485  long long nsecs = nsecTaiToAny(_nsecs, scale);
486  ts.tv_sec = static_cast<time_t>(nsecs / LL_NSEC_PER_SEC);
487  ts.tv_nsec = static_cast<int>(nsecs % LL_NSEC_PER_SEC);
488  return ts;
489 }
struct timespec timespec(Timescale scale) const
Get date as a timespec struct, with time in seconds and nanoseconds.
Definition: DateTime.cc:482

◆ timeval()

struct timeval lsst::daf::base::DateTime::timeval ( Timescale  scale) const

Get date as a timeval struct, with time in seconds and microseconds.

Parameters
[in]scaledesired time scale (TAI, TT or UTC)
Returns
date as a timeval struct
Exceptions
lsst.pex.exceptions.DomainErrorif scale is UTC and the UTC date is before 1961-01-01
lsst.pex.exceptions.RuntimeErrorif DateTime is invalid

Definition at line 464 of file DateTime.cc.

491  {
492  _assertValid();
493  struct timeval tv;
494  long long nsecs = nsecTaiToAny(_nsecs, scale);
495  tv.tv_sec = static_cast<time_t>(nsecs / LL_NSEC_PER_SEC);
496  tv.tv_usec = static_cast<int>((nsecs % LL_NSEC_PER_SEC) / 1000);
497  return tv;
498 }

◆ toString()

std::string lsst::daf::base::DateTime::toString ( Timescale  scale) const

Get date as an ISO8601-formatted string.

The returned format is: yyyy-mm-ddThh:mm:ss.sssssssssZ where the final Z is only present if scale is UTC

Parameters
[in]scaleDesired time scale (TAI, TT or UTC).
Exceptions
lsst.pex.exceptions.DomainErrorif scale is UTC and the UTC date is before 1961-01-01
lsst.pex.exceptions.RuntimeErrorif DateTime is invalid

Definition at line 500 of file DateTime.cc.

500  {
501  _assertValid();
502  struct tm gmt(this->gmtime(scale));
503 
504  long long fracnsecs = nsecTaiToAny(_nsecs, scale) % LL_NSEC_PER_SEC;
505  if (fracnsecs < 0) {
506  fracnsecs += LL_NSEC_PER_SEC;
507  }
508  auto fmtStr = scale == UTC ? "%04d-%02d-%02dT%02d:%02d:%02d.%09dZ" : "%04d-%02d-%02dT%02d:%02d:%02d.%09d";
509  return (boost::format(fmtStr) % (gmt.tm_year + 1900) % (gmt.tm_mon + 1) % gmt.tm_mday % gmt.tm_hour %
510  gmt.tm_min % gmt.tm_sec % fracnsecs)
511  .str();
512 }
struct tm gmtime(Timescale scale) const
Get date as a tm struct, with truncated fractional seconds.
Definition: DateTime.cc:466

Friends And Related Function Documentation

◆ boost::serialization::access

friend class boost::serialization::access
friend

Definition at line 291 of file DateTime.h.

Member Data Documentation

◆ invalid_nsecs

constexpr long long lsst::daf::base::DateTime::invalid_nsecs = std::numeric_limits<std::int64_t>::min()
staticconstexpr

Definition at line 75 of file DateTime.h.


The documentation for this class was generated from the following files: