[LEAPSECS] BBC radio Crowd Science
Brooks Harris
brooks at edlmax.com
Tue Jan 31 13:29:40 EST 2017
On 2017-01-30 04:39 PM, Tom Van Baak wrote:
>>> 2017-01-01T00:00:36.5 - 36 s = 2016-12-31T23:59:60.5
>> What kind of arithmetic is that?
> Hi Michael,
>
> First, there's no problem with this, right? (Thanks to Steve for catching typo)
>
> 2017-01-01T00:00:35.5 TAI = 2016-12-31T23:59:59.5 UTC
> 2017-01-01T00:00:36.5 TAI = 2016-12-31T23:59:60.5 UTC
> 2017-01-01T00:00:37.5 TAI = 2017-01-01T00:00:00.5 UTC
>
> Now, we want to use "UTC = TAI + (UTC - TAI)" notation. So which is correct:
>
> 2017-01-01T00:00:35.5 TAI - 36 s = 2016-12-31T23:59:59.5 UTC
> 2017-01-01T00:00:36.5 TAI - 36 s = 2016-12-31T23:59:60.5 UTC ??
> 2017-01-01T00:00:37.5 TAI - 37 s = 2017-01-01T00:00:00.5 UTC
>
> or
>
> 2017-01-01T00:00:35.5 TAI - 36 s = 2016-12-31T23:59:59.5 UTC
> 2017-01-01T00:00:36.5 TAI - 37 s = 2016-12-31T23:59:60.5 UTC ??
> 2017-01-01T00:00:37.5 TAI - 37 s = 2017-01-01T00:00:00.5 UTC
>
> Neither one is particularly clear to me. Of course in real code it all works because you special case the leap second label discontinuity and make it work. In a sense you replace normal sexagesimal arithmetic with 59-gesimal or 61-gesimal arithmetic for that one minute. But, yeah, I can see that it complicates prose and equations regarding UTC-TAI offsets.
>
>
>
I think its the first one >>
2017-01-01T00:00:36.5 TAI - 36 s = 2016-12-31T23:59:60.5 UTC ??
2017-01-01T00:00:37.5 TAI - 37 s = 2017-01-01T00:00:00.5 UTC
The Leap Second accrues to the TAI-UTC value immediately after the Leap
Second.
As Steve Summit said earlier (with his 2015 example)
Positive leap second:
TAI UTC TAI-UTC
00:00:34.0 23:59:59.0 35
00:00:34.5 23:59:59.5 35
00:00:35.0 23:59:60.0 35
00:00:35.5 23:59:60.5 35
00:00:36.0 00:00:00.0 36
00:00:36.5 00:00:00.5 36
Here, in Steve's example, I think the notation is appropriate. The
YMDhms columns are titled "TAI" and "UTC". Too often in the literature,
and sometimes in standards specifications, we see a "date" but no
explanation of what timescale the YMDhms representation is referring to.
Usually, it means UTC, which I take to mean "Gregorian calendar
algorithm with Leap Second compensation applied". But sometimes a YMDhms
form is used to express TAI, in which case its what I'd call "pure"
Gregorian, that is, with no Leap Second compensation.
To extend the 2016/2017 example more completely:
Two Leap Second metadata variables are required to support positive Leap
Seconds:
1) TAI-UTC value
2) Is Leap Second - flag marking the actual Leap Second
TAI seconds - seconds-since-TAI1958
YMDhms (TAI) - YMDhms encoding by "pure Gregorian" of seconds-since-TAI1958
TAI-UTC - TAI-UTC value (initial 10s calibration at UTC1972 plus Leap
Seconds)
UTC seconds - (seconds-since-TAI1958 - TAI-UTC)
LS - Is Leap Second (0 or 1)
YMDhms (UTC) - YMDhms encoding of (seconds-since-TAI1958 - TAI-UTC) by
"Leap Second compensated Gregorian"
TAI seconds YMDhms (TAI) TAI-UTC UTC seconds LS YMDhms (UTC)
1861920035.0 = 2017-01-01T00:00:35.0 - 36 = 1861919999.0 0 =
2016-12-31T23:59:59.0
1861920035.5 = 2017-01-01T00:00:35.5 - 36 = 1861919999.5 0 =
2016-12-31T23:59:59.5
1861920036.0 = 2017-01-01T00:00:36.0 - 36 = 1861920000.0 1 =
2016-12-31T23:59:60.0
1861920036.5 = 2017-01-01T00:00:36.5 - 36 = 1861920000.5 1 =
2016-12-31T23:59:60.5
1861920037.0 = 2017-01-01T00:00:37.0 - 37 = 1861920000.0 0 =
2017-00-00T00:00:00.0
1861920037.5 = 2017-01-01T00:00:37.5 - 37 = 1861920000.5 0 =
2017-00-00T00:00:00.5
1861920038.0 = 2017-01-01T00:00:38.0 - 37 = 1861920001.0 0 =
2017-00-00T00:00:01.0
Attached - TAIToUTCDemoConsole - a rudimentary c program using POSIX
gmtime() (a pure, strict gmtime() with 1 second resolution) demonstrates
one way to make the calculations. Its output:
2016-2017 Leap Second
TAI seconds YMDhms (TAI) TAI-UTC UTC seconds LS YMDhms (UTC)
1861920035 = 2017-01-01 00:00:35 - 36 = 1861919999 0 = 2016-12-31 23:59:59
1861920036 = 2017-01-01 00:00:36 - 36 = 1861920000 1 = 2016-12-31 23:59:60
1861920037 = 2017-01-01 00:00:37 - 37 = 1861920000 0 = 2017-01-01 00:00:00
1861920038 = 2017-01-01 00:00:38 - 37 = 1861920001 0 = 2017-01-01 00:00:01
-Brooks
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://pairlist6.pair.net/pipermail/leapsecs/attachments/20170131/fb000700/attachment.html>
-------------- next part --------------
//TAIToUTCDemoConsole.h
#ifndef TAIToUTCDemoConsole_h_included
#define TAIToUTCDemoConsole_h_included
/**************************
TAI seconds to YMDhms (UTC)
Demonstrates methods for calculating YMDhms UTC from TAI seconds
using classic POSIX gmtime()
(strict time_t and gmtime() operate on integral seconds)
Two Leap Second metadata variables are required
to support positive Leap Seconds:
1) TAI-UTC value
2) Is Leap Second - flag marking the actual Leap Second
Negative Leap Seconds are not supported
Brooks Harris 2017-01-31
**************************/
#include <stdio.h>
#include <time.h>
#include <memory.h> // memset
////////////////////////
// MSVC 6.0 does not support "ll" printf() directive or long long data type.
// MSVC 6.0 printf() requires "I64" to forant __it64 types
// this is a stupid hack/work-around
//
// The MSVC version replaces any "ll" with "I64"
// and calls vprintf() with modifief formatMod
//
// The Linux verion makes no changes and calls vprintf()
//
// USE: If a printf() format is to include a 64-bit display
// printf64() with "%lld" or "%llu" instead of standard printf()
int __cdecl printf64(
const char *format,
...
);
////////////////////////
#ifdef _MSC_VER
// MSVC //////////////
#include <stdarg.h> // for va_start
#include <string.h> // strcpy()
typedef unsigned __int64 uint64_t;
typedef __int64 int64_t;
int __cdecl printf64(
const char *format,
...
)
{
// replace any "ll" with "I64"
// and vprintf() with formatMod
char formatMod[64];
memset(formatMod, 0, sizeof(formatMod));
char* pFormatChar = (char*)format;
char *pstrstrll = NULL;
int i1stllPos = 0;
int iMax = strlen(format);
int iCnt = 0;
int iCntMod = 0;
while(1)
{
if(iCnt > iMax)
break;
pstrstrll = strstr( pFormatChar, "ll" );
if(pstrstrll)
i1stllPos = pstrstrll - format;
if(i1stllPos && iCnt == i1stllPos)
{
strcat(formatMod, "I64");
iCntMod += 3;
pFormatChar += 2;
iCnt += 2;
i1stllPos = 0;
}
else
{
formatMod[iCntMod] = *pFormatChar;
iCntMod++;
pFormatChar++;
iCnt++;
}
}
va_list arglist;
va_start(arglist, format);
return vprintf(formatMod, arglist);
}
// MSVC //////////////
#else // #ifdef _MSC_VER
// LINUX /////////////
#include <inttypes.h>
int __cdecl printf64(
const char *format,
...
)
{
// Linux //////////////
// no format changes
// call vprintf() with format
va_list arglist;
va_start(arglist, format);
return vprintf(format, arglist);
// Linux //////////////
}
///////////////////////
#endif // #ifdef _MSC_VER
#define STOP_CONSOLE_ON_COMPLETION_IF_YOU_WANT
#ifdef STOP_CONSOLE_ON_COMPLETION_IF_YOU_WANT
#include <conio.h>
#endif // STOP_CONSOLE_ON_COMPLETION_IF_YOU_WANT
#endif // #ifndef TAIToUTCDemoConsole_h_included
-------------- next part --------------
// TAIToUTCDemoConsole.cpp
/**************************
TAI seconds to YMDhms (UTC)
Demonstrates methods for calculating YMDhms UTC from TAI seconds
using classic POSIX gmtime()
(strict time_t and gmtime() operate on integral seconds)
Two Leap Second metadata variables are required
to support positive Leap Seconds:
1) TAI-UTC value
2) Is Leap Second - flag marking the actual Leap Second
Negative Leap Seconds are not supported
Brooks Harris 2017-01-31
**************************/
////////////////////////////////////////////////////////
////////////////////////////////////////////////////////
#include "TAIToUTCDemoConsole.h"
int TAISecondsToYMDhmsUTC(int64_t i64SecondsSinceTAI1958,
int iTAI_UTC,
bool bIsLeapSecond)
{
// define offset TAI1958 to Posix 1970 epoch
#define OFFSET_TAI1958_To_UTC1970_378691210 378691210
time_t time_tUTC = 0;
tm* ptmUTC = NULL;
// UTC seconds = TAI seconds - TAI-UTC
int64_t i64SecondsUTC = i64SecondsSinceTAI1958 - iTAI_UTC;
// to Posix 1970 epoch
time_tUTC = (time_t)i64SecondsUTC - OFFSET_TAI1958_To_UTC1970_378691210 + 10;
/////////////////////////
// calculate YMDhms (UTC),
// Gregorian with Leap Second compensation
if(bIsLeapSecond)
time_tUTC--; // decrement to yield "YYYY-MM-DD 23:59:59"
// calculate YMDhms UTC
ptmUTC = gmtime(&time_tUTC);
if(bIsLeapSecond)
ptmUTC->tm_sec = 60;// overwrite tm_sec 59 with 60
// this is entirely illegal for strict POSIX
// but strftime() will format it OK
char sTmYMDhmsUTC[128];
sTmYMDhmsUTC[0] = 0;
strftime( sTmYMDhmsUTC, sizeof(sTmYMDhmsUTC),
"%Y-%m-%d %H:%M:%S", ptmUTC);
/////////////////////////
/////////////////////////
// calculate YMDhms (TAI)
// 'pure' Gregorian with no compensation
// TAI seconds to Posix 1970 epoch
time_t time_tTAI = (time_t)i64SecondsSinceTAI1958 -
OFFSET_TAI1958_To_UTC1970_378691210 + 10;
tm* ptmTAI = NULL;
ptmTAI = gmtime(&time_tTAI);
char sTmYMDhmsTAI[128];
sTmYMDhmsTAI[0] = 0;
strftime( sTmYMDhmsTAI, sizeof(sTmYMDhmsTAI),
"%Y-%m-%d %H:%M:%S", ptmTAI);
/////////////////////////
printf64("%010lld = %s - %d = %010lld %d = %s\n",
i64SecondsSinceTAI1958,
sTmYMDhmsTAI,
iTAI_UTC,
i64SecondsUTC,
bIsLeapSecond ? 1 : 0,
sTmYMDhmsUTC);
return 0;
}
int main(int argc, char* argv[])
{
int64_t i64SecondsSinceTAI1958 = 0; // 1958-01-01T00:00:00 (TAI)
int iTAI_UTC = 0; // not set
bool bIsLeapSecond = false; // Is Leap Second
printf("2016-2017 Leap Second\n");
printf("TAI seconds YMDhms (TAI) TAI-UTC UTC seconds LS YMDhms (UTC)\n");
// begin at 2017-01-01T00:00:35 (TAI)
// 2016-12-31T23:59:59 (UTC)
i64SecondsSinceTAI1958 = 1861920035; // 2017-01-01T00:00:35 (TAI)
iTAI_UTC = 36; // no increment
bIsLeapSecond = false; // NOT Leap Second
TAISecondsToYMDhmsUTC(i64SecondsSinceTAI1958, iTAI_UTC, bIsLeapSecond);
// the Leap Second at 2016-12-31T23:59:60 (UTC)
i64SecondsSinceTAI1958++;
iTAI_UTC = 36; // no increment
bIsLeapSecond = true; // IS Leap Second !!!!
TAISecondsToYMDhmsUTC(i64SecondsSinceTAI1958, iTAI_UTC, bIsLeapSecond);
// 2017-01-01T00:00:00 (UTC)
i64SecondsSinceTAI1958++;
iTAI_UTC = 37; // increment TAI-UTC !!!!
bIsLeapSecond = false; // NOT Leap Second
TAISecondsToYMDhmsUTC(i64SecondsSinceTAI1958, iTAI_UTC, bIsLeapSecond);
// 2017-01-01T00:00:01 (UTC)
i64SecondsSinceTAI1958++;
iTAI_UTC = 37; // no increment
bIsLeapSecond = false; // NOT Leap Second
TAISecondsToYMDhmsUTC(i64SecondsSinceTAI1958, iTAI_UTC, bIsLeapSecond);
/////////////////////
#define STOP_CONSOLE_ON_COMPLETION_IF_YOU_WANT
#ifdef STOP_CONSOLE_ON_COMPLETION_IF_YOU_WANT
_getch();
#endif // STOP_CONSOLE_ON_COMPLETION_IF_YOU_WANT
return 0;
}
More information about the LEAPSECS
mailing list