LSSTApplications  19.0.0-14-gb0260a2+72efe9b372,20.0.0+7927753e06,20.0.0+8829bf0056,20.0.0+995114c5d2,20.0.0+b6f4b2abd1,20.0.0+bddc4f4cbe,20.0.0-1-g253301a+8829bf0056,20.0.0-1-g2b7511a+0d71a2d77f,20.0.0-1-g5b95a8c+7461dd0434,20.0.0-12-g321c96ea+23efe4bbff,20.0.0-16-gfab17e72e+fdf35455f6,20.0.0-2-g0070d88+ba3ffc8f0b,20.0.0-2-g4dae9ad+ee58a624b3,20.0.0-2-g61b8584+5d3db074ba,20.0.0-2-gb780d76+d529cf1a41,20.0.0-2-ged6426c+226a441f5f,20.0.0-2-gf072044+8829bf0056,20.0.0-2-gf1f7952+ee58a624b3,20.0.0-20-geae50cf+e37fec0aee,20.0.0-25-g3dcad98+544a109665,20.0.0-25-g5eafb0f+ee58a624b3,20.0.0-27-g64178ef+f1f297b00a,20.0.0-3-g4cc78c6+e0676b0dc8,20.0.0-3-g8f21e14+4fd2c12c9a,20.0.0-3-gbd60e8c+187b78b4b8,20.0.0-3-gbecbe05+48431fa087,20.0.0-38-ge4adf513+a12e1f8e37,20.0.0-4-g97dc21a+544a109665,20.0.0-4-gb4befbc+087873070b,20.0.0-4-gf910f65+5d3db074ba,20.0.0-5-gdfe0fee+199202a608,20.0.0-5-gfbfe500+d529cf1a41,20.0.0-6-g64f541c+d529cf1a41,20.0.0-6-g9a5b7a1+a1cd37312e,20.0.0-68-ga3f3dda+5fca18c6a4,20.0.0-9-g4aef684+e18322736b,w.2020.45
LSSTDataManagementBasePackage
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 306 of file DateTime.cc.

306 : _nsecs(DateTime::invalid_nsecs) {}

◆ 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 308 of file DateTime.cc.

308 : _nsecs(nsecAnyToTai(nsecs, scale)) {}

◆ 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 310 of file DateTime.cc.

310  {
311  switch (system) {
312  case MJD:
313  setNsecsFromMjd(date, scale);
314  break;
315  case JD:
316  setNsecsFromJd(date, scale);
317  break;
318  case EPOCH:
319  setNsecsFromEpoch(date, scale);
320  break;
321  default:
322  throw LSST_EXCEPT(pexEx::InvalidParameterError, "DateSystem must be MJD, JD, or EPOCH");
323  break;
324  }
325 }

◆ 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 327 of file DateTime.cc.

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

◆ 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 385 of file DateTime.cc.

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

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 429 of file DateTime.cc.

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

◆ 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 463 of file DateTime.cc.

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

◆ hash_value()

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

Return a hash of this object.

Definition at line 515 of file DateTime.cc.

515 { 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 527 of file DateTime.cc.

527  {
528  Leap l;
529  leapSecTable.clear();
530  boost::regex re(
531  "^\\d{4}.*?=JD\\s*([\\d.]+)\\s+TAI-UTC=\\s+([\\d.]+)\\s+S"
532  " \\+ \\(MJD - ([\\d.]+)\\) X ([\\d.]+)\\s*S$");
533  for (boost::cregex_iterator i = make_regex_iterator(leapString.c_str(), re);
534  i != boost::cregex_iterator(); ++i) {
535  double mjdUtc = strtod((*i)[1].first, 0) - MJD_TO_JD;
536  l.offset = strtod((*i)[2].first, 0);
537  l.mjdRef = strtod((*i)[3].first, 0);
538  l.drift = strtod((*i)[4].first, 0);
539  l.whenUtc = static_cast<long long>((mjdUtc - EPOCH_IN_MJD) * NSEC_PER_DAY);
540  l.whenTai = l.whenUtc + static_cast<long long>(1.0e9 * (l.offset + (mjdUtc - l.mjdRef) * l.drift));
541  leapSecTable.push_back(l);
542  }
543 }

◆ 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 517 of file DateTime.cc.

517  {
518  struct timeval tv;
519  int ret = gettimeofday(&tv, 0);
520  if (ret != 0) {
521  throw LSST_EXCEPT(lsst::pex::exceptions::RuntimeError, "Unable to get current time");
522  }
523  long long nsecs = tv.tv_sec * LL_NSEC_PER_SEC + tv.tv_usec * 1000LL;
524  return DateTime(nsecs, DateTime::UTC);
525 }

◆ 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 447 of file DateTime.cc.

447  {
448  if (!isValid()) {
449  // return the same invalid value for all time scales
451  }
452  return nsecTaiToAny(_nsecs, scale);
453 }

◆ operator==()

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

Definition at line 513 of file DateTime.cc.

513 { 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 463 of file DateTime.cc.

481  {
482  _assertValid();
483  struct timespec ts;
484  long long nsecs = nsecTaiToAny(_nsecs, scale);
485  ts.tv_sec = static_cast<time_t>(nsecs / LL_NSEC_PER_SEC);
486  ts.tv_nsec = static_cast<int>(nsecs % LL_NSEC_PER_SEC);
487  return ts;
488 }

◆ 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 463 of file DateTime.cc.

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

◆ 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 499 of file DateTime.cc.

499  {
500  _assertValid();
501  struct tm gmt(this->gmtime(scale));
502 
503  long long fracnsecs = nsecTaiToAny(_nsecs, scale) % LL_NSEC_PER_SEC;
504  if (fracnsecs < 0) {
505  fracnsecs += LL_NSEC_PER_SEC;
506  }
507  auto fmtStr = scale == UTC ? "%04d-%02d-%02dT%02d:%02d:%02d.%09dZ" : "%04d-%02d-%02dT%02d:%02d:%02d.%09d";
508  return (boost::format(fmtStr) % (gmt.tm_year + 1900) % (gmt.tm_mon + 1) % gmt.tm_mday % gmt.tm_hour %
509  gmt.tm_min % gmt.tm_sec % fracnsecs)
510  .str();
511 }

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:
lsst::daf::base::DateTime::isValid
bool isValid() const
Is this date valid?
Definition: DateTime.h:203
std::string
STL class.
std::string::size
T size(T... args)
lsst::daf::base::DateTime::timeval
struct timeval timeval(Timescale scale) const
Get date as a timeval struct, with time in seconds and microseconds.
Definition: DateTime.cc:490
lsst::afw::table._match.first
first
Definition: _match.py:74
std::regex_match
T regex_match(T... args)
lsst.pex.config.history.format
def format(config, name=None, writeSourceLine=True, prefix="", verbose=False)
Definition: history.py:174
lsst::daf::base::DateTime::EPOCH
@ EPOCH
Definition: DateTime.h:66
lsst.pex::exceptions::DomainError
Reports arguments outside the domain of an operation.
Definition: Runtime.h:57
lsst::daf::base::DateTime::timespec
struct timespec timespec(Timescale scale) const
Get date as a timespec struct, with time in seconds and nanoseconds.
Definition: DateTime.cc:481
std::string::c_str
T c_str(T... args)
std::atoi
T atoi(T... args)
lsst::daf::base::DateTime::invalid_nsecs
constexpr static long long invalid_nsecs
Definition: DateTime.h:75
std::string::erase
T erase(T... args)
lsst::daf::base::DateTime::DateTime
DateTime()
Default constructor: construct an invalid DateTime.
Definition: DateTime.cc:306
lsst::daf::base::DateTime::MJD
@ MJD
Definition: DateTime.h:66
LSST_EXCEPT
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Definition: Exception.h:48
lsst::daf::base::DateTime::JD
@ JD
Definition: DateTime.h:66
lsst::afw::cameraGeom::ReadoutCorner::LL
@ LL
lsst::daf::base::DateTime::UTC
@ UTC
Definition: DateTime.h:70
lsst.pex::exceptions::InvalidParameterError
Reports invalid arguments.
Definition: Runtime.h:66
lsst::daf::base::DateTime::TAI
@ TAI
Definition: DateTime.h:69
min
int min
Definition: BoundedField.cc:103
std::strtod
T strtod(T... args)
lsst::afw.display.ds9.scale
def scale(algorithm, min, max=None, frame=None)
Definition: ds9.py:109
lsst::daf::base::DateTime::nsecs
long long nsecs(Timescale scale=TAI) const
Get date as nanoseconds since the unix epoch.
Definition: DateTime.cc:447
lsst.pex::exceptions::RuntimeError
Reports errors that are due to events beyond the control of the program.
Definition: Runtime.h:104
lsst::daf::base::DateTime::TT
@ TT
Definition: DateTime.h:71
std::hash
lsst::daf::base::DateTime::gmtime
struct tm gmtime(Timescale scale) const
Get date as a tm struct, with truncated fractional seconds.
Definition: DateTime.cc:465