Abstract:

Dates and the results of date arithmetic are exchanged throughout the world using the international standards "Data elements and interchange formats — Information interchange — Representation of dates and times" (ISO 8601:2004) assembled by the International Organization for Standardization (ISO). When accountants, actuaries and other financial services analysts use the R Statistical Environment ("R") for creating models, they have access to tried-and-true implementations of those standards through R's offering of two "objects" ("classes") to the user: POSIXt and Date. The ability of those two classes to satisfy a broad range of date/time requirements has been an important factor in R's rise in popularity as a scientific analytical tool.

However, those two objects are somewhat unsatisfactory in the financial industry for modeling two key accounting concepts: accounting date and account aging in month units.

The purpose of this paper is show how to define ISO-compliant implementations of accounting date and elapsed time in units of months in an R package.

Background

Representing time instants in R

Base R -- version r paste(R.version$major, R.version$minor, sep=".") as of this writing -- uses two general "classes" (objects with special properties) for representing instants in time, POSIXct and POSIXlt, modeled after the Portable Operating System Interface ("POSIX") standards for UNIX operating systems.^[IEEE Std 1003.1, a.k.a. "POSIX.1.", is a standard for computer operating systems that covers a variety of topics, including software structures for representing time. Much information can be found online; see for example http://www.opengroup.org/austin/papers/backgrounder.html.] Historical background for these classes can be found in the original paper "Date-Time Classes" by Brian Ripley and Kurt Hornik.^[R News, 1/2, p. 9. http://www.r-project.org/doc/Rnews/Rnews_2001-2.pdf]

The POSIXct class (the "c" stands for "calendar time") is built around a numeric that holds the (potentially fractional) number of seconds since the beginning of January 1, 1970 "in the UTC time zone."^[See R's help for "DateTimeClasses". R help on a topic can be read by invoking the function help at the console with the topic name in quotes, e.g., help("POSIXt"). A shorthand version uses the question mark alone -- ?POSIXt -- often found in the footnotes herein.] To borrow the words of Ripley and Hornik^["Date-Time Classes"], this representation of time "is not easily digestible" by the user.

The POSIXlt class is a list of a sufficient number of elements such as "year", "mon", "hour", "sec", etc. so as to completely determine an instant of time in the user's local time zone and communicate that instant to the user. Per ?POSIXlt, the "l" stands for "local", but could also stand for "list." In most cases the technical distinctions between the two classes are of little concern to the user, with the possible exception of "time zone." Here is an example of a possible source of confusion.

Let the R variable a represent the first instant of 1970, which of course occurs zero seconds "after the beginning of 1970." R requires that the 1970 "origin" be provided because POSIXct objects can potentially reference off of any time point.

a <- as.POSIXct(0, origin="1970-01-01")
a

To display a at the console, R uses a POSIXlt object in the background. Because the timezone was not set explicitly when a was defined, POSIXlt assumes the user's local time zone (Pacific Standard Time for this author). That time-zone shift between the user's definition of a and R's regurgitation of a's value can be confusing. If time-zone distinctions are not important, that confusion can be avoided by always working in the "UTC time zone." it was still 8pm December 31st on the California coast, but that was not how a was defined so that is not how one might expect a to appear when printed. The reason a displays in local (PST) time is that R uses the POSIXlt class at the intermediary between POSIXct and the character representation to the user, which, as mentioned previously, defaults to the user's local time zone. To confirm for yourself that a really does hold the value "zero seconds after the beginning of 1970", simply strip away the accoutrements surrounding a with the unclass function:

unclass(a)

So "under the hood" a is simply the number 0 (zero) with a "tzone" attribute (which R uses to drive its date/time "class" behavior). To force R to represent a in the UTC time zone, one option is to use the format function with the tz argument as follows:^[Other options exist. For a good summary, see David Smith's blog "Converting time zones in R: tips, tricks and pitfalls," Revolutions, June 02, 2009, http://blog.revolutionanalytics.com/2009/06/converting-time-zones.html. See also the with_tz function in the lubridate package on CRAN: https://cran.r-project.org/web/packages/lubridate/index.html]

format(a, tz="UTC")

In the remainder of this paper it will be assumed that the timezone is

t <- seq(0,2*pi,length=100) 
coords <- t(rbind(sin(t), cos(t))) 
plot(coords, type="l", axes=F, xlab="", ylab="", xlim=c(-1.2,1.2), ylim=c(-1.2,1.2))
a <- -3
r <- sqrt(a*a+1)
t <- seq(-atan(-1/a), atan(-1/a), length=100)
lines(a+r*cos(t), 0+r*sin(t), lty="dotted")
lines(-(a+r*cos(t)), 0+r*sin(t), lty="dotted", col="gray")
lines(0+r*sin(t), a+r*cos(t), lty="dotted", col="gray")
lines(0+r*sin(t), -(a+r*cos(t)), lty="dotted", col="black")
#text(0, 1, "0", pos=3)
text(.2, -.1, "0", pos=1)
text(0, .7, "UTC", pos=4)

The Date Class

The Date class in R holds the number of days since the beginning of January 1, 1970.

It will be important to visit a few "basic concepts" that people understand intuitively but must be defined precisely if computers are to understand too:

time interval

Definition: time interval
A time interval is "part of the time axis limited by two instants. [It] comprises all instants between the two limiting instants and, unless otherwise stated, the limiting instants themselves."^[ISO 8601 2.1.3]

Figure 1 below is a diagram of two time intervals A and B. Each includes its respective endpoints as indicated by the square brackets. A and B overlap at time point 1.

op <- par(no.readonly = TRUE)

n=3
par(mar=c(1,2,1,2))
par(lend="butt")
plot(c(0,n), c(0,0), col="black", type = "l", 
     axes=F, xlim=c(0,n+.15), ylim=c(-.5, .5), 
     xlab="", ylab="")
axis(1, pos=0, labels=FALSE, tick=FALSE)

arrows(x0=-.1, y0=0, x1=n+.15, length=.1)
text(n+.1, 0, "t", pos = 1)

axis(1, at=0:2, pos=0)
axis(1, at=seq(from=0, to=2, length.out=2*24+1), tcl=par("tcl")*.5, labels=FALSE, pos=0)

segments(x0=0.01, y0=0, x1=0.99, col="blue", lwd =4)
text(x=0.013, y=0, "[", col="blue", font = 2, cex=2)
text(x=0.987, y=0, "]", col="blue", font = 2, cex=2)
text(x=0.5, y= .1, "A", col="blue")

segments(x0=1.01, y0=0, x1=1.99, col="blue", lwd =4)
text(x=1.013, y=0, "[", col="blue", font = 2, cex=2)
text(x=1.987, y=0, "]", col="blue", font = 2, cex=2)
text(x=1.5, y= .1, "B", col="blue")

box("outer")
par(op)

Time intervals are generally endowed with more evocative names than "A" and "B", however. For example, if Figure 1 is a diagram of the first few days of calendar year 1970, then more descriptive names for calendar days A and B would be "1970-01-01" and "1970-01-02", using ISO 8601's "complete representation" of a calendar date.^[ISO 8601:2004 4.1.2.2] Those names also apply to all time instants enclosed by the endpoints. This leads to some ambiguity in this example because midnight between January 1st and 2nd is included in both intervals. Such ambiguity can be easily avoided, however, by leaving one of the endpoints "open."

In the case of calendar days, the question is how to represent midnight.

Midnight

Section 4.2.3 of ISO 8601 says that midnight between January 1st and 2nd, 1970 can be represented as either
  Hour 00) 1970-01-02 00:00:00 or
  Hour 24) 1970-01-01 24:00:00.
"The choice of representation ... will depend upon any association with a date, or a time interval."^[ISO 8601:2004 4.2.3]

In the design of an experiment, it seeem natural to associate the beginning of the experiment as belonging to the first time period of the experiment. That suggests a time interval that is closed on the left and open on the right where the initiation of a time interval is included in the interval. Base R's POSIXt implementation follows the hour 00 approach.

POSIXt

Base R's "POSIXt" classes of objects store time as the number of seconds that have elapsed since the beginning of 1970. Midnight is the first instant of a calendar day. That is easily seen. Here we tell R to store midnight ending January 1, 1970 in the variable a. R is smart enough to understand the hour 24 notation. However, when we ask R to print that value back to us at the console, it says that the time point represented in the variable a is a member of the second day of January.

a <- as.POSIXct("1970-01-01 24:00:00", tz = "UTC")
print(a)

Figure 2 below is an illustration of a few of the calendar days surrounding the transition from 1969 to 1970, where the endpoints of the time intervals are represented by POSIXt objects. Since hour 00 begins each day, calendar days are represented by left-closed/right-open time intervals. The endpoints are modeled by POSIXt objects.

op <- par(no.readonly = TRUE)

n = 3
a <- as.POSIXct((-n:n)*60*60*24, origin = "1970-01-01 00:00:00", tz="UTC")
par(mar=c(1,2,1,2))
par(lend="butt")
NDaysInSecs <- 60*60*24*n
RadiusOfWindow <- NDaysInSecs + 60*60*24
plot(a, y=rep(0, 2*n+1), type = "l", axes = F, 
     ylim=c(-1, 1), xlim = c(-RadiusOfWindow, RadiusOfWindow),
     xlab="", ylab="")
axis(1, at=a, labels=a, pos=0)
arrows(x0=a[1]-60*60*24, y0=0, x1=a[2*n+1]+60*60*24, length=.1, code = 2)
text(a[2*n+1]+60*60*12, 0, "t", pos = 1)
segments(x0=a[1:(2*n)], y0=0, x1=a[2:(2*n+1)], col="blue", lwd =4)
for (i in 1:(2*n)) text(x=a[i] + 15*60, y=0, "[", col="blue", font = 2, cex=2)
for (i in 2:(2*n+1)) text(x=a[i] - 15*60, y=0, ")", col="blue", font = 2, cex=2)
axis(2, pos=0, labels = FALSE, lwd.ticks=0, lty="dotted")
text(0, .8, "origin =\n\"1970-01-01 00:00:00\"", pos=1)

box("outer")
par(op)

R's left-closed/right-open paradigm runs consistently throughout its representation of time intervals. In Figure 3 below are shown five different time intervals in increasing magnitude. Calendar day, calendar month, and calendar year are defined terms in ISO 8601:2004. "Calendar second, minute and hour" are represented in the same spirit.

Each interval has a "label" (a "mark" in 8601 terminology, also called a "name" in R) corresponding to the instant beginning the interval. Note that all first intervals in Fugure 4 are labeled "1970-01-01". This is an example of R being "helpful": if the instant corresponds to midnight, R only shows the date.^[In R, see argument format under help for strftime.] For example, to show the full date and time for the first instant of 1970 try the format specifier "%Y-%m-%d %H:%M:%S".

FirstInstant <- as.POSIXlt(0, origin="1970-01-01", tz="UTC")
format(FirstInstant, usetz=FALSE)
format(FirstInstant, format = "%Y-%m-%d %H:%M:%S", usetz=FALSE)
op <- par(no.readonly = TRUE)
par(mfrow=c(5,1))
par(mar=c(1,2,1,2))
par(lend="butt")
xlab.y <- -.45
# second
n=3
plot(c(0,n), c(0,0), col="black", type = "l", 
     axes=F, xlim=c(0,n+.15), ylim=c(-.5, .5), 
     xlab="", ylab="")
axis(1, pos=0, labels=FALSE, tick=FALSE)
text(n/2, xlab.y, "\"calendar second\" (undefined in ISO 8601:2004)")

arrows(x0=-.1, y0=0, x1=n+.15, length=.1)
text(n+.1, 0, "t", pos = 1)

# major ticks
axis(1, at=0:n, pos=0) 
# minor ticks
axis(1, at=seq(from=0, to=n, length.out=n*10+1), tcl=par("tcl")*.5, labels=FALSE, pos=0)

for (i in 1:n){
  segments(x0=(i-1)+0.01, y0=0, x1=i-.01, col="blue", lwd =4)
  text(x=(i-1)+0.013, y=0, "[", col="blue", font = 2, cex=2)
  text(x=i-0.013, y=0, ")", col="blue", font = 2, cex=2)
  text(x=(i-.5), y= .1, col="blue", 
       labels=format(as.POSIXct((i-1), origin="1970-01-01", tz="UTC")
#                     , format="%Y-%m-%d %H:%M:%S"
                     )
       )
}


# minute
n=3
plot(c(0,n), c(0,0), col="black", type = "l", 
     axes=F, xlim=c(0,n+.15), ylim=c(-.5, .5), 
     xlab="", ylab="")
axis(1, pos=0, labels=FALSE, tick=FALSE)
text(n/2, xlab.y, "\"calendar minute\" (undefined in ISO 8601:2004)")

arrows(x0=-.1, y0=0, x1=n+.15, length=.1)
text(n+.1, 0, "t", pos = 1)

# major ticks
axis(1, at=0:n, pos=0) 
# minor ticks
axis(1, at=seq(from=0, to=n, length.out=n*60+1), tcl=par("tcl")*.5, labels=FALSE, pos=0)

for (i in 1:n){
  segments(x0=(i-1)+0.01, y0=0, x1=i-.01, col="blue", lwd =4)
  text(x=(i-1)+0.013, y=0, "[", col="blue", font = 2, cex=2)
  text(x=i-0.013, y=0, ")", col="blue", font = 2, cex=2)
  text(x=(i-.5), y= .1, col="blue", 
       labels=format(as.POSIXct((i-1)*60, origin="1970-01-01", tz="UTC")
#                     , format="%Y-%m-%d %H:%M:%S"
                     )
       )
}

# hour
n=3
plot(c(0,n), c(0,0), col="black", type = "l", 
     axes=F, xlim=c(0,n+.15), ylim=c(-.5, .5), 
     xlab="", ylab="")
axis(1, pos=0, labels=FALSE, tick=FALSE)
text(n/2, xlab.y, "\"calendar hour\" (undefined in ISO 8601:2004)")

arrows(x0=-.1, y0=0, x1=n+.15, length=.1)
text(n+.1, 0, "t", pos = 1)

# major ticks
axis(1, at=0:n, pos=0) 
# minor ticks
axis(1, at=seq(from=0, to=n, length.out=n*60+1), tcl=par("tcl")*.5, labels=FALSE, pos=0)

for (i in 1:n){
  segments(x0=(i-1)+0.01, y0=0, x1=i-.01, col="blue", lwd =4)
  text(x=(i-1)+0.013, y=0, "[", col="blue", font = 2, cex=2)
  text(x=i-0.013, y=0, ")", col="blue", font = 2, cex=2)
  text(x=(i-.5), y= .1, col="blue", 
       labels=format(as.POSIXct((i-1)*60*60, origin="1970-01-01", tz="UTC")
#                     , format="%Y-%m-%d %H:%M:%S"
                     )
       )
}

# day
n=3
plot(c(0,n), c(0,0), col="black", type = "l", 
     axes=F, xlim=c(0,n+.15), ylim=c(-.5, .5), 
     xlab="", ylab="")
axis(1, pos=0, labels=FALSE, tick=FALSE)
text(n/2, xlab.y, "calendar day (ISO 8601:2004 2.2.6)")

arrows(x0=-.1, y0=0, x1=n+.15, length=.1)
text(n+.1, 0, "t", pos = 1)

# major ticks
axis(1, at=0:n, pos=0) 
# minor ticks
axis(1, at=seq(from=0, to=n, length.out=n*24+1), tcl=par("tcl")*.5, labels=FALSE, pos=0)

for (i in 1:n){
  segments(x0=(i-1)+0.01, y0=0, x1=i-.01, col="blue", lwd =4)
  text(x=(i-1)+0.013, y=0, "[", col="blue", font = 2, cex=2)
  text(x=i-0.013, y=0, ")", col="blue", font = 2, cex=2)
  text(x=(i-.5), y= .1, col="blue", 
       labels=format(as.POSIXct((i-1)*60*60*24, origin="1970-01-01", tz="UTC")
#                     , format="%Y-%m-%d %H:%M:%S"
                     )
       )
}

# month
n=3
plot(c(0,n), c(0,0), col="black", type = "l", 
     axes=F, xlim=c(0,n+.15), ylim=c(-.5, .5), 
     xlab="", ylab="")
axis(1, pos=0, labels=FALSE, tick=FALSE)
text(n/2, xlab.y, "calendar month (ISO 8601:2004 2.2.11)")

arrows(x0=-.1, y0=0, x1=n+.15, length=.1)
text(n+.1, 0, "t", pos = 1)

# major ticks
axis(1, at=0:n, pos=0) 
# minor ticks
axis(1, at=seq(from=0, to=n, length.out=n*30+1), tcl=par("tcl")*.5, labels=FALSE, pos=0)

for (i in 1:n){
  segments(x0=(i-1)+0.01, y0=0, x1=i-.01, col="blue", lwd =4)
  text(x=(i-1)+0.013, y=0, "[", col="blue", font = 2, cex=2)
  text(x=i-0.013, y=0, ")", col="blue", font = 2, cex=2)
  text(x=(i-.5), y= .1, col="blue", 
       labels=format(ISOdate(1970, i, 1, 0, 0, 0, tz="UTC")
#                     , format="%Y-%m-%d %H:%M:%S"
                     )
       )
}


box("outer")
par(op)

Although R's choice of hour 00 is understandable and defensible, it is nevertheless arbitrary. The hour 24 choice could just as arbitrarily have been made, in which case the intervals in figure 2 would have been left-open/right-closed. Indeed, if Figure 2 were rotated around the origin, the resulting diagram would illustrate a sequence of left-open/right-closed time intervals.

op <- par(no.readonly = TRUE)

par(mar=c(1,2,1,2))
par(lend="butt")
NDaysInSecs <- 60*60*24*n
RadiusOfWindow <- NDaysInSecs + 60*60*24
a1 <- rev(a)
plot(a1, y=rep(0, length(a1)), type = "l", axes = F, 
     ylim=c(-1, 1), xlim = c(RadiusOfWindow, -RadiusOfWindow),
     xlab="", ylab="")
axis(1, at=a, labels=a, pos=0)
arrows(x0=a[1]-60*60*24, y0=0, x1=a[2*n+1]+60*60*24, length=.1, code = 2)
text(a[2*n+1]+60*60*12, 0, "t", pos = 1)
segments(x0=a[1:(2*n)], y0=0, x1=a[2:(2*n+1)], col="blue", lwd =4)
for (i in 1:(2*n)) text(x=a[i] + 15*60, y=0, "]", col="blue", font = 2, cex=2)
for (i in 2:(2*n+1)) text(x=a[i] - 15*60, y=0, "(", col="blue", font = 2, cex=2)
axis(2, pos=0, labels = FALSE, lwd.ticks=0, lty="dotted")
text(0, .8, "origin =\n\"1970-01-01 00:00:00\"", pos=1)

box("outer")
par(op)

Labeling an interval

rotate around origin -- "dual"

"cut"

leap seconds occur at midnight beginning July 1st's UTC as necessary

format(.leap.seconds, format = "%Y-%m-%d %H:%M:%S", tz="UTC",usetz=TRUE)

? strptime

Remember that in most time zones some times do not occur and some occur twice because of transitions to/from ‘daylight saving’ (also known as ‘summer’) time. strptime does not validate such times (it does not assume a specific time zone), but conversion by as.POSIXct will do so. Conversion by strftime and formatting/printing uses OS facilities and may return nonsensical results for non-existent times at DST transitions.

?DateTimeClasses

Unfortunately, the conversion is complicated by the operation of time zones and leap seconds (26 days have been 86401 seconds long so far, the last at the time of writing being added in 2015: the times of the extra seconds are in the object .leap.seconds). The details of this are entrusted to the OS services where possible. It seems that some rare systems used to use leap seconds, but all known current platforms ignore them (as required by POSIX). This is detected and corrected for at build time, so "POSIXct" times used by R do not include leap seconds on any platform.

A few times have specific issues. First, the leap seconds are ignored, and real times such as "2005-12-31 23:59:60" are (probably) treated as the next second. However, they will never be generated by R, and are unlikely to arise as input. Second, on some OSes there is a problem in the POSIX/C99 standard with "1969-12-31 23:59:59 UTC", which is -1 in calendar time and that value is on those OSes also used as an error code. Thus as.POSIXct("1969-12-31 23:59:59", format = "%Y-%m-%d %H:%M:%S", tz = "UTC") may give NA, and hence as.POSIXct("1969-12-31 23:59:59", tz = "UTC") will give "1969-12-31 23:59:00". Other OSes (including the code used by R on Windows) report errors separately and so are able to handle that time as valid.

Fractional seconds are printed only if options("digits.secs") is set: see strftime.

duration

A duration is the "non-negative quantity ['magnitude'] attributed to a time interval, the value of which is equal to the difference between the time points of the final instant and the initial instant of the time interval."^[ISO 8601 2.1.6]

Think of a duration as the length of the vector ("magnitude") representing a time interval. In the figure below, the magnitude of the vector is one -- second, day, month, etc. -- depending on the context.

par(mar=c(1,2,1,2))
plot(2, 0, xlim=c(0,5), ylim=c(-.5, .5), col="green", pch = 20, axes=F, 
     xlab="", ylab="", main="duration")
arrows(x0=2, y0=0, x1=3, col="green", lwd =2)
box()

Under the International System of Units (SI), the base unit of duration is "seconds". Indeed, whenever a duration is expressed in units other than "seconds" that length of time is referred to as a "nominal duration."^[ISO 8601 2.1.7] Examples of nominal durations are calendar day (its length in seconds can vary depending on leap seconds and daylight/standard time shifts), calendar month (its length in seconds varies, in addition to calendar day variability, due to differing numbers of calendar days in a month), and calendar year (in addition to calendar day variability, its length can vary due to the addition of a leap day). We will see examples of this behavior in R below.

seconds

seconds are the base unit for expressing duration.

As pertains R, that means ages need not rely on classes as granular as POSIXt; the Date class, which keeps track of calendar days, should suffice.

When a contract specifies an inception date but no time, e.g., an insurance policy, for the event E corresponding to the financial responsibilities incepting therein, it is customary to consider those responsibilities to start at hour 00. When considering the age of the aggregation of events occurring during a time interval, financial and accounting models will "tag" those events with the same instant of inception. Two general instants can be found, particularly in the actuarial literature:

  1. the beginning instant of the interval
  2. the midpoint of the interval.

It would seem that the calculation of an age in units of "days" would be straightforward, but there are a couple of complicating factors. First, ISO 8601 defines a "day" to be the unit of time equal to exactly 24 hours. It defines a "calendar day" to be the interval of time between successive midnights. Those calendar day intervals are usually one day in length, but for two exceptions:

  1. Leap seconds: Every once in a while a second must be added to or subtracted from Coordinated Universal Time (UTC) to realign UTC solar time (UT1).

  2. Daylight time: Frequently the clock is adjusted by local authorities.

r 60*60*24 == 86400 r 86400*30 == 2592000

r as.Date("2015-12-01") - as.Date("2015-11-01") # Time difference of 30 days

r as.POSIXct("2015-12-01") - as.POSIXct("2015-11-01") # Time difference of 30.04167 days

r as.POSIXct("2015-12-01 00:00:00") - as.POSIXct("2015-11-01 00:00:00") # Time difference of 30.04167 days

r as.character(difftime(as.POSIXct("2015-12-01 00:00:00"), as.POSIXct("2015-11-01 00:00:00"), units = "sec")) # Time difference of 2595600 secs

r 2595600 - 2592000 == 3600

r 3600 == 60*60 # 1 hour

Accounting Date

Definition: Accounting Date
An accounting date is the cutoff date for reflecting events and recording amounts as paid or unpaid in a financial statement or accounting system. The accounting date is sometimes referred to as the “as of” date.^[Casualty Actuarial Society Statement of Principles Regarding Property and Casualty Unpaid Claims Estimates]

Although financial statements are always stated as of a date, say, December 31, 2015, it would be more thorough to assign a time as well, so as to identify all transactions impacting the financial statements as of that date. Some say "any particular moment on the 31st" could be used.^["it would be more accurate to write December 31, 20XX, 11:59:59, or any particular moment on the 31st." http://www.investopedia.com/university/accounting/accounting5.asp] However, payments can potentially occur up to and including midnight December 31, 2015, so if a time designator is to be used, midnight would be the most appropriate.

Another reason for the closing instant to be the end of the day is for the purposes of date arithmetic. For example, the instant closing the month of December is 31 days from the beginning of December.

The International Organization for Standardization (ISO) sets the standards for computer representation of dates and times as a string of characters.^[ISO 8601:2004, Data elements and interchange formats -- Information interchange -- Representation of dates and times, (c) ISO 2004] Regarding "midnight", the standards recognize that the instant 24:00:00 (hour 24) marking the end of one calendar day coincides with the instant 00:00:00 (hour 00) marking the start of the next calendar day. Furthermore, "the choice of [hour 24 or hour 00] will depend upon any association with a date, or a time interval. [Hour 24] representations are preferred to represent the end of a time interval."^[ISO 8601 4.2.3. Emphasis added.] The concept of the closing of the books at the end of a calendar year, calendar month or calendar day^[defined as "time intervals" by ISO 8601] suggests that hour 24 is preferred for representing an accounting date.

ISO 8601's representation of the accounting date referred to as "close of the 2015 calendar year" or "as of year end 2015" is therefore "2015-12-31 24:00:00".

On the other hand, base R's implementation of the 8601 standards^[The POSIXt classes. In R see ?DateTimeClasses. For additional background, see https://en.wikipedia.org/wiki/Unix_time] stores time as the number of seconds since the beginning of 1970, so midnight is represented as hour 00 of the beginning of each day. Therefore, the representation of "as of year end 2015" in R is "2016-01-01 00:00:00" which is January 1st when shortened to just the date.^[ISO 8601 2.1.5 recognizes that a "date" can represent an instant in time as well as a span of time ("duration").] However, to refer to the accounting date "as of year end 2015" with a label that uses the month "January" does not satisfactorily communicate the "as of December 31, 2015" accounting date concept.

It would be preferable that R and a user be able to communicate that concept using a label with "December" in it and also have that label refer to the instant in time separating calendar years 2015 and 2016 (as.Date("2016-01-01") in R).

That is the purpose of the "asof" class in the mondate package.

Elapsed Month: "emonth"

Definition: Age
The age of event E as of accounting date A is the length of time from the occurrence of event E to hour 24 on accounting date A.

Note that units are not mentioned in the definition of age. This is because the appropriate unit will be specific to the use case. In the vast majority of accounting cases, age is measured in units of days, months or years, not seconds.

It turns out that the definitions of units days, months and years in ISO 8601 is not particularly straightforward, with complexity in proportion to the width of the unit. Due to the fundamental monthly, quarterly, and yearly accounting cycles, it is generally not productive to used data defined more granularly than "month", but even that level of granularity has its complexities.

This paper adds to that complexity with another take on "month": "emonth."

There is little ambiguity in defining elapsed time (durations) in units of days. ISO 8601 defines a R's two Date/Time classes facilitate date/time arithmetic in uits of seconds and days.

so elapsed time in units of seconds is easily combined with a POSIXt object to yield another POSIXt object unambiguously.

It is more complicated with units of months because month periods are comprised of different numbers of days. But this complication can be overcome with two key observations.

  1. It is commonly accepted that the length of time between the beginning and end of a month is one "month".

  2. Given any time t in any given month, there is a unique portion p, 0<=p<=1, that represents the portion of the month completed by time t. Conversely, given any portion p, the point in time of a month completed as of that portion of the month can be easily found.

Those two observations give rise to the definition of the "month-time" of an instant in time:

Definition: Month Time
The month time of time t is a real number measuring the number of months since the beginning of 1970 to time t. The fractional part of the real number represents the portion of t's month to have expired by time t.

R has two classes, POSIXlt and POSIXct

Sentence B

Base R follows that standard and represents an instant of time as the number of seconds that have transpired since the beginning of 1970.

It is well known that "months" are comprised of different numbers of days. Although it is widely accepted that the length of time between the beginning and end of a month is one "month", it is also recognized that month durations cannot be defined consistently in units of days. Those observations give rise to a different type of unit: "elapsed month" or "emonth".

Definition: Elapsed Month ("emonth")
The length of time between two instants in time t1 and t2 in units of "emonths" is
mondate(t2) - mondate(t1) where mondate(t) is a real number representing the number of months between the beginning of 1970 and time t.

Example
mondate("1970-02-01") = 1
mondate("1971-01-01") = 12 mondate("1970-02-15 00:00:00") = 1.5 because the beginning of February 15, 1970 is halfway through February 1970. as.Date("1971-01-01") - as.Date("1971-02-01") = 10.5 emonths

Conversely, given any real number t, it is straightforward to find the time ?YYYYMMDD?HH:MM:SS.zzzzz? that is t months away from the beginning of 1970 by first counting whole months, then counting into the next month (if necessary) the number of days and seconds corresponding to that month per the fractional value of t.

Defintion: Elapsed Years
The number of elapsed years between times t1 and t2 equals the number of elapsed months divided by 12.

Case Study:

ABC Ins. Co. started on 1/1/2010 to write earthquake insurance in California. As claims are made, ABC defines the occurrence date of a claim claim to be the date of the earthquake and stores that date in an ISO-8601 compliant object (POSIXt). ABC has had good luck so far -- only 20 claims have been made. Here are their occurrence dates and their know values as of 12/31/2015:

data ?

To complete Sentence B, we need one more definition:

Definition: The age of accident year AY as of AOD is AOD - AY-01-01.

The accident year age of the 20 claims is the vector
mondate(?2015-12-31?) ? year(occurrenceDate)-01-01

http://smallbusiness.chron.com/differences-dates-between-balance-sheet-income-sheet-24881.html

"Balance Sheet Date A balance sheet often states that it is prepared as of a specific date, referred to as the balance sheet date. The balance sheet reports on a company’s financial conditions, namely the values of the company’s assets, liabilities and shareholders’ equity. Values are measured in terms of their monetary amounts at particular points in time rather than over any periods. At the end of an accounting cycle, with the accounting books closed to recording new business transactions, companies can summarize their financial conditions as of the cycle's end."

http://www.casact.org/professionalism/standards/princip/SOP-Regarding-Property-and-Casualty-Unpaid-Claims-Estimates_Final%204-22-2015.pdf

Appendix A: Two Universal Time Standards

Two time standards in common use today are Universal Time ("UT1") and Coordinated Universal Time ("UTC").

UT1 is a time standard based on the rotation of the earth. It starts with mean solar time at zero degrees longitude (a.k.a., the Prime Meridian), which is the longitude on which is located the Royal Greenwich Observatory. Mean solar time, in turn, starts with "apparent" solar time, which defines a "solar day" as the time period between two "noons", where a "noon" is the moment when the sun reaches its zenith during the day. Apparent solar time is the time one would see on a sundial. It turns out that a solar day is not a constant 86,400=60x60x24 seconds in length but changes each day due to the eliptical orbit of the earth. ^[https://en.wikipedia.org/wiki/Time_standard https://en.wikipedia.org/wiki/Universal_Time#Versions] The average length of a solar day over the course of a year is called a "mean solar day." "Currently a mean solar day is about 86,400.002 SI seconds.[2]"

Bibliography

I asked David Madore about his CLOCK_UTC and friends website: http://www.madore.org/~david/computers/unix-leap-seconds.html. He answered my email on 2015-12-14 and included some references:
http://www.cl.cam.ac.uk/~mgk25/iso-time.html

This second reference at the end has a good summary of how the acronyms UTC, TAI, and ISO do not match the order of the words in English or French:

https://groups.google.com/forum/#!msg/comp.std.unix/GaIQpDHUl1U/nnlJgCfZZb8J

Here is a pretty good summary:
https://www.eecis.udel.edu/~ntp/ntpfaq/NTP-s-time.htm#Q-UTC

http://tycho.usno.navy.mil/leapsec.html

https://igscb.jpl.nasa.gov/mail/igsmail/1997/msg00096.html

Dennis McCarthy
Director of Time, U.S. Naval Observatory

https://en.wikipedia.org/wiki/Universal_Time#Versions

The rotation of the Earth is somewhat irregular, and is very gradually slowing due to tidal acceleration.

http://maia.usno.navy.mil/

The United States' contribution to the international standards is handled by the U.S. Naval Observatory:

"The IERS Rapid Service/Prediction Center is the product center of the International Earth Rotation and Reference Systems Service responsible for providing Earth orientation parameters (EOPs) on a rapid turnaround basis. This service is primarily intended for real-time users and others needing the highest quality EOP information sooner than is available in the IERS final series (Bulletin B) published by the IERS Earth Orientation Center, which is based at the Observatoire de Paris."

"This Center is an activity of the Earth Orientation (EO) Department at the U.S. Naval Observatory (USNO). The mission of the USNO includes determining the positions and motions of celestial bodies, measuring the Earth's rotation and orientation, maintaining the master clock for the U.S., and disseminating precise time (atomic and astronomical). The EO Dept. contributes to this mission by collecting suitable observations and performing data analyses to determine and predict the time-varying orientation of the terrestrial reference frame within the quasi-inertial celestial reference frame. The key parameters determined and disseminated are polar motion coordinates, Universal Time (UT1), precession, and nutation. The user community is very broadly based, the main applications involving principally high-accuracy navigation and positioning, particularly in real-time and near real-time modes."

"Contact Information: 202-762-1518 (primary); 202-550-6407 (alternate); 202-762-1444 (alternate)"

DMM: It would appear that the USNO uses JPL software. Here is a link to that software: http://ssd.jpl.nasa.gov/?planet_eph_export. Here is a website that suggests JPL is in charge of ephemeral time rather than the USNO: https://en.wikipedia.org/wiki/Newcomb%27s_Tables_of_the_Sun

Here is a USNO site that defines leap seconds: http://tycho.usno.navy.mil/leapsec.html

That site also defines

ephemeris second
"the fraction 1/31,556,925.9747 of the tropical year for 1900 January 0 at 12 hours ephemeris time." Note that there are r prettyNum(60*60*24*365, big.mark = ",") "seconds" in a 365-day year, where a "day" equals 24 hours, an "hour" equals 60 minutes, and a "minute" equals 60 seconds. There are r prettyNum(60*60*24*366, big.mark = ",") "seconds" in a 366-day year (leap year). If a leap year comes around every four years, then there are about

prettyNum(60*60*24*365*.75 + 60*60*24*366*.25, big.mark = ",")

This definition of the ephemeris second was ratified by the Eleventh General Conference on Weights and Measures in 1960. Thus, Ephemeris Time (ET) is defined as "the measure of time that brings the observed positions of the celestial bodies into accord with the Newtonian dynamical theory of motion."^[http://tycho.usno.navy.mil/leapsec.html]

"Following several years of work, two astronomers at the U.S. Naval Observatory (USNO) and two astronomers at the National Physical Laboratory (Teddington, England) determined the relationship between the frequency of the cesium atom (the standard of time) and the ephemeris second. They determined the orbital motion of the Moon about the Earth, from which the apparent motion of the Sun could be inferred, in terms of time as measured by an atomic clock. As a result, in 1967 the Thirteenth General Conference on Weights and Measures defined the second of atomic time in the International System of Units (SI) as

the duration of 9,192,631,770 periods of the radiation corresponding to the transition between the two hyperfine levels of the ground state of the cesium 133 atom.

The ground state is defined at zero magnetic field. The second thus defined is equivalent to the ephemeris second."

http://maia.usno.navy.mil/ser7/ser7.dat

26 November 2015 Vol. XXVIII No. 048

Sample from the UT1-UTC Table

                MJD      x(arcsec)   y(arcsec)   UT1-UTC(sec)              
   2015 11 27  57353       0.1178      0.2540      0.13841         
   2015 11 28  57354       0.1163      0.2541      0.13711         
   2015 11 29  57355       0.1146      0.2542      0.13582         
   2015 11 30  57356       0.1129      0.2543      0.13449         
   2015 12  1  57357       0.1110      0.2542      0.13312         
   2015 12  2  57358       0.1092      0.2540      0.13171         
   2015 12  3  57359       0.1074      0.2538      0.13026

https://msdn.microsoft.com/en-us/library/ms973825.aspx

Performing date and time calculations on values that represent machine local time may not always yield the correct result. When performing calculations on time values in time-zone contexts that practice daylight savings time, you should convert values to universal time representations before performing date arithmetic calculations.

There are several advantages to performing calculations using UCT time. Chief among them is the fact that when represented in universal time, every day has a fixed length, and there are no time-zone offsets to deal with.

The recommended format strings for converting DateTime to strings are: 'yyyy'-'MM'-'dd'T'HH': 'mm': 'ss.fffffff'Z' —For UCT values 'yyyy'-'MM'-'dd'T'HH': 'mm': 'ss.fffffff'zzz' —For local values 'yyyy'-'MM'-'dd'T'HH': 'mm': 'ss.fffffff' —For abstract time values

http://www.diffen.com/difference/GMT_vs_UTC

Greenwich Mean Time (GMT) is a term originally referring to mean solar time at the Royal Observatory, Greenwich where a system was first developed around 1850 for tracking time based on the rotation of the Earth. It is now often used to refer to Coordinated Universal Time (UTC) when this is viewed as a time zone.

Strictly speaking, UTC is not a time zone but an atomic time scale which only approximates GMT in the old sense. It is also used to refer to Universal Time (UT), which is an astronomical concept that directly replaced the original GMT.

In 1970 the Coordinated Universal Time system was devised by an international advisory group of technical experts within the International Telecommunication Union (ITU). UTC is the International Atomic Time (TAI, from the French Temps atomique international) with leap seconds added at irregular intervals to compensate for the Earth's slowing rotation. Leap seconds are used to allow UTC to closely track UT1, which is the mean solar time at the Royal Observatory, Greenwich.

The ITU felt it was best to designate a single abbreviation for use in all languages in order to minimize confusion. Since unanimous agreement could not be achieved on using either the English word order, CUT (coordinated universal time), or the French word order, TUC (temps universel coordonné), the acronym UTC was chosen as a compromise.

The difference between UTC and UT1 cannot exceed 0.9 s, so if high precision is not required, the general term Universal Time (without a suffix) may be used.

In casual use, Greenwich Mean Time (GMT) is the same as UTC and UT1. Owing to the ambiguity of whether UTC or UT1 is meant, and because timekeeping laws usually refer to UTC, GMT is avoided in careful writing.

http://www.diffen.com/difference/GMT_vs_UTC

Video says "UTC ... is an offset of the prime meridian"

Comparison chart

            GMT                               UTC

Stands for Greenwich Mean Time Coordinated Universal Time (Abbreviated From The French Name) Refers To A Time Zone A System Of Time-Keeping Usage By Human Readable Clocks By Digitally Synchronized Clocks Measured Using Rotation Of Earth (Historically) Atomic Transition Principle (Periodic updates with astronomical time)

http://stackoverflow.com/questions/14986043/is-gmt-same-as-utc

I am running a world targeted website where people from all over the world visit. The database contains time in International Date Line West format. I am taking the user time zone using JavaScript and converting the time in the database to user's time and then showing on the page. I want to ask that is International Date Line West is correct format for world level website? Or setting to UTC or GMT will be better? And what is the difference between UTC and GMT and International Date Line West? Are these three same? Finally what time should I set onto my server that will be converted using offset of timezone of user?

If you're interested in astronomical observations, for example of satellites such as GPS, or if you want to cite a technical standard (ITU-R TF.460-6), then you might care that we use UTC and that GMT no longer has a precise definition. Otherwise you probably consider GMT to be the same thing as UTC, and also consider UT and UT1 to be the same as UTC--which technically they are not.

Also, if you're tracking computer criminals or other distributed activity, then you need to determine whether certain events at various sites may or may not have occurred before certain other events. For that purpose you will want to learn and use Network Time Protocol (NTP). That will have a much bigger effect on your understanding of time than the little differences between UTC, UT1, and UT.

"International Date Line West" is just a friendly name for a timezone where the time is defined as twelve hours less than UTC (that is, UTC-12).

https://en.wikipedia.org/wiki/Atomic_clock

An atomic clock is a clock device that uses an electronic transition frequency in the microwave, optical, or ultraviolet region[2] of the electromagnetic spectrum of atoms as a frequency standard for its timekeeping element. Atomic clocks are the most accurate time and frequency standards known, and are used as primary standards for international time distribution services, to control the wave frequency of television broadcasts, and in global navigation satellite systems such as GPS.

National standards agencies in many countries maintain a network of atomic clocks which are intercompared and kept synchronized to an accuracy of 10^(-9) seconds per day (approximately 1 part in 1014). These clocks collectively define a continuous and stable time scale, International Atomic Time (TAI). For civil time, another time scale is disseminated, Coordinated Universal Time (UTC). UTC is derived from TAI, but approximately synchronised, by using leap seconds, to UT1, which is based on actual rotation of the Earth with respect to the solar time.

https://en.wikipedia.org/wiki/Solar_time

The effect of this is that a clock running at a constant rate – e.g. completing the same number of pendulum swings in each hour – cannot follow the actual Sun; instead it follows an imaginary "mean Sun" that moves along the celestial equator at a constant rate that matches the real Sun's average rate over the year.[1] This is "mean solar time", which is still not perfectly constant from one century to the next but is close enough for most purposes. Currently a mean solar day is about 86,400.002 SI seconds.[2]

https://en.wikipedia.org/wiki/Earth's_rotation

The Earth rotates once in about 24 hours with respect to the sun and once every 23 hours, 56 minutes and 4 seconds with respect to the stars (see below). Earth's rotation is slowing slightly with time; thus, a day was shorter in the past. This is due to the tidal effects the Moon has on Earth's rotation. Atomic clocks show that a modern-day is longer by about 1.7 milliseconds than a century ago,[1] slowly increasing the rate at which UTC is adjusted by leap seconds.

http://www.timeanddate.com/time/gmt-utc-time.html

Greenwich Mean Time (GMT) is often interchanged or confused with Coordinated Universal Time (UTC). But GMT is a time zone and UTC is a time standard.

Although GMT and UTC share the same current time in practice, there is a basic difference between the two:

GMT is a time zone officially used in some European and African countries. The time can be displayed using both the 24-hour format (0 - 24) or the 12-hour format (1 - 12 am/pm). UTC is not a time zone, but a time standard that is the basis for civil time and time zones worldwide. This means that no country or territory officially uses UTC as a local time.

Universal time

https://en.wikipedia.org/wiki/Universal_Time#Versions

Universal Time (UT) is a time standard based on Earth's rotation. It is a modern continuation of Greenwich Mean Time (GMT), i.e., the mean solar time on the Prime Meridian at Greenwich. In fact, the expression "Universal Time" is ambiguous (when accuracy of better than a few seconds is required), as there are several versions of it, the most commonly used being Coordinated Universal Time (UTC) and UT1 (see below).[1] All of these versions of UT, except for UTC, are based on Earth's rotation relative to distant celestial objects (stars and quasars), but with a scaling factor and other adjustments to make them closer to solar time. UTC is based on International Atomic Time, with leap seconds added to keep it within 0.9 second of UT1.

Versions There are several versions of Universal Time:

UT0 is Universal Time determined at an observatory by observing the diurnal motion of stars or extragalactic radio sources, and also from ranging observations of the Moon and artificial Earth satellites. The location of the observatory is considered to have fixed coordinates in a terrestrial reference frame (such as the International Terrestrial Reference Frame) but the position of the rotational axis of the Earth wanders over the surface of the Earth; this is known as polar motion. UT0 does not contain any correction for polar motion. The difference between UT0 and UT1 is on the order of a few tens of milliseconds. The designation UT0 is no longer in common use.[11] UT1 is the principal form of Universal Time. While conceptually it is mean solar time at 0° longitude, precise measurements of the Sun are difficult. Hence, it is computed from observations of distant quasars using long baseline interferometry, laser ranging of the Moon and artificial satellites, as well as the determination of GPS satellite orbits. UT1 is the same everywhere on Earth, and is proportional to the rotation angle of the Earth with respect to distant quasars, specifically, the International Celestial Reference Frame (ICRF), neglecting some small adjustments. The observations allow the determination of a measure of the Earth's angle with respect to the ICRF, called the Earth Rotation Angle (ERA, which serves as a modern replacement for Greenwich Mean Sidereal Time). UT1 is required to follow the relationship ERA = 2pi(0.7790572732640 + 1.00273781191135448Tu) radians where Tu = (Julian UT1 date - 2451545.0)[12]

UTC (Coordinated Universal Time) is an atomic timescale that approximates UT1. It is the international standard on which civil time is based. It ticks SI seconds, in step with TAI. It usually has 86,400 SI seconds per day but is kept within 0.9 seconds of UT1 by the introduction of occasional intercalary leap seconds. As of 2015, these leaps have always been positive (the days which contained a leap second were 86,401 seconds long). Whenever a level of accuracy better than one second is not required, UTC can be used as an approximation of UT1. The difference between UT1 and UTC is known as DUT1.[15]

https://commons.wikimedia.org/wiki/File:World_Time_Zones_Map.png

By TimeZonesBoy (US Central Intelligence Agency) [Public domain], via Wikimedia Commons (Attribution not legally required)

David Smith's blog "Converting time zones in R: tips, tricks and pitfalls," Revolutions, June 02, 2009 http://blog.revolutionanalytics.com/2009/06/converting-time-zones.html

Lubridate
Grolemund, Garrett and Hadley Wickham, "Dates and Times Made Easy with lubridate", Journal of Statistical Software, April 2011, Volume 40, Issue 3.

Today is r format(Sys.Date(), format = "%B %d, %Y")

Ripley, Brian D. and Kurt Hornik, "Date-Time Classes", R News, Vol. 1/2, June 2001. [https://www.r-project.org/doc/Rnews/Rnews_2001-2.pdf]

POSIX.1
http://www.opengroup.org/austin/papers/backgrounder.html
http://www.opengroup.org/austin/papers/posix_faq.html

From ?strptime References

The POSIX 1003.1 standard, which is in some respects stricter than ISO 8601.

See LC_TIME in Base Definitions: Detailed ToC

file:///Users/danielmurphy/Downloads/susv4tc1/basedefs/toc.html

See folder susv4tc1 in mondate vignettes folder

file:///Users/danielmurphy/Downloads/susv4tc1/basedefs/V1_chap07.html#tag_07_03_05

Here's a pretty good paper about dates, Lubridate, Chron: http://biostat.mc.vanderbilt.edu/wiki/pub/Main/ColeBeck/datestimes.pdf



chiefmurph/mondate documentation built on Aug. 29, 2022, 4:13 p.m.