How to calculate epoch day? - datetime

Is calculating the epoch day as simple as taking the epoch seconds and dividing by 86400? Or are there some special calculations that need to be done to take account of daylight savings or leap year or some other factor?
Update: by "epoch day" I mean number of days since the epoch.

POSIX defines that you can deduce the number of days since The Epoch (1970-01-01 00:00:00Z) by dividing the timestamp by 86400. This deliberately and consciously ignores leap seconds.
See the definition Seconds since the Epoch:
4.15 Seconds Since the Epoch
A value that approximates the number of seconds that have elapsed since the Epoch. A Coordinated Universal Time name (specified in terms of seconds (tm_sec), minutes (tm_min), hours (tm_hour), days since January 1 of the year (tm_yday), and calendar year minus 1900 (tm_year)) is related to a time represented as seconds since the Epoch, according to the expression below.
If the year is <1970 or the value is negative, the relationship is undefined. If the year is >=1970 and the value is non-negative, the value is related to a Coordinated Universal Time name according to the C-language expression, where tm_sec, tm_min, tm_hour, tm_yday, and tm_year are all integer types:
tm_sec + tm_min*60 + tm_hour*3600 + tm_yday*86400 +
(tm_year-70)*31536000 + ((tm_year-69)/4)*86400 -
((tm_year-1)/100)*86400 + ((tm_year+299)/400)*86400
The relationship between the actual time of day and the current value for seconds since the Epoch is unspecified.
How any changes to the value of seconds since the Epoch are made to align to a desired relationship with the current actual time is implementation-defined. As represented in seconds since the Epoch, each and every day shall be accounted for by exactly 86400 seconds.
Note:
The last three terms of the expression add in a day for each year that follows a leap year starting with the first leap year since the Epoch. The first term adds a day every 4 years starting in 1973, the second subtracts a day back out every 100 years starting in 2001, and the third adds a day back in every 400 years starting in 2001. The divisions in the formula are integer divisions; that is, the remainder is discarded leaving only the integer quotient.

Related

Convert UTC ISO string date to Unix timestamp

I have this UTC date in a Google spreadsheet: 2018-10-18T08:55:13Z and would like to convert it to Unix timestamp (1539852913). I tried this formula, but it's unable to recognize the timevalue:
=DATEVALUE(MID(A1;1;10)) + TIMEVALUE(MID(A1;12;8))
If I can get a valid date and time, I can use this formula to convert to Unix timestamp:
=(A1-$C$1)*86400
Does anyone have a solution for this?
Simpler:
=86400*(left(substitute(A1,"T"," "),19))-2209161600
Replaces T with space and cuts off Z, leaving what's left recognisable as date and time in arithmetical calculations. Convert day and time index into seconds and adjust for the offset.
Assuming your date has proceeding zeros for single digit days and month, pull each date string part and drop it into the DATE formula as follows:
Year
=LEFT(A1,4)
Month
=MID(A1,6,2)
Day
=MID(A1,9,2)
Use the date formula
=DATE(year,month,day)
=DATE(LEFT(A1,4),MID(A1,6,2),MID(A1,9,2))
A similar process can be used for TIME
Hour
=MID(A1,12,2)
Minutes
=MID(A1,15,2)
Seconds
=MID(A1,18,2)
Time
=TIME(Hour,Minutes,Seconds)
=TIME(MID(A1,12,2),MID(A1,15,2),MID(A1,18,2))
1) There are other methods
2) The formulas will need to be adapted if you do not have leading 0 for each unit. In that case you would need to use FIND to identify the position of key characters and measure the distance between them to determine if there was a single digit unit or double digit unit.
Since the date is the integer part (left of the decimal) represents the number of days since 1900/01/01 (with that date being 1) and decimal portion represents time in terms of fraction of a day, to get a full date and time, you would add the date formula to the time formula as follows:
=DATE(LEFT(A1,4),MID(A1,6,2),MID(A1,9,2))+TIME(MID(A1,12,2),MID(A1,15,2),MID(A1,18,2))

Is IDL able to add / subtract from date?

As you can see the question above, I was wondering if IDL is able to add or subtract days / months / years to a given date.
For example:
given_date = anytim('01-jan-2000')
print, given_date
1-Jan-2000 00:00:00.000
When I would add 2 weeks to the given_date, then this date should appear:
15-Jan-2000 00:00:00.000
I was already looking for a solution for this problem, but I unfortunately couldn't find any solution.
Note:
I am using a normal calendar date, not the julian date.
Are you only concerned with dates after 1582? Is accuracy to the second important?
The ANYTIM routine is not part of the IDL distribution. Possibly there are third party routines to handle time increments, but I don't know of any builtin to the IDL library.
By default, which you are using, ANYTIM returns seconds from Jan 1, 1979. So to add/subtract some number of days, weeks, or years, you could calculate the number of seconds in the time interval. Of course, this does not take into account leap seconds/years (but leap years are fairly easy to take into account, leap seconds requires a database of when they were added). And adding months is going to require determining which month so to determine the number of days in it.
IDL can convert to and from Julian dates using JULDAY and CALDAT.
You may also read and write Julian dates (which are doubles or long integers) to and from strings using the format keyword to PRINT, STRING, and READS.
You'll want to use the (C()) calendar date format code.
format='(c(cdi0,"-",cMoa,"-"cyi04," ",cHi02,":",cmi02,":",csf06.3))'
date = julday(1, 1, 2000)
print, date, format=format
; 1-Jan-2000 00:00:00.000
date = date + 14
print, date, format=format
; 15-Jan-2000 00:00:00.000

convert difftime time to years, months and days

How can I accurately convert the products (units is in days) of the difftime below to years, months and days?
difftime(Sys.time(),"1931-04-10")
difftime(Sys.time(),"2012-04-10")
This does years and days but how could I include months?
yd.conv<-function(days, print=TRUE){
x<-days*0.00273790700698851
x2<-floor(x)
x3<-x-x2
x4<-floor(x3*365.25)
if (print) cat(x2,"years &",x4,"days\n")
invisible(c(x2, x4))
}
yd.conv(difftime(Sys.time(),"1931-04-10"))
yd.conv(difftime(Sys.time(),"2012-04-10"))
I'm not sure how to even define months either. Would 4 weeks be considered a month or the passing of the same month day. So for the later definition of a month if the initial date was 2012-01-10 and the current 2012-05-31 then we'd have 0 years, 5 months and 21 days. This works well but what if the original date was on the 31st of the month and the end date was on feb 28 would this be considered a month?
As I wrote this question the question itself evolved so I'd better clarify:
What would be the best (most logical approach) to defining months and then how to find diff time in years, months and days?
If you're doing something like
difftime(Sys.time(), someDate)
It comes as implied that you must know what someDate is. In that case, you can convert this to a POSIXct class object that gives you the ability to extract temporal information directly (package chron offers more methods, too). For instance
as.POSIXct(c(difftime(Sys.time(), someDate, units = "sec")), origin = someDate)
This will return your desired date object. If you have a timezone tz to feed into difftime, you can also pass that directly to the tz parameter in as.POSIXct.
Now that you have your date object, you can run things like months(.) and if you have chron you can do years(.) and days(.) (returns ordered factor).
From here, you could do more simple math on the difference of years, months, and days separately (converting to appropriate numeric representations). Of course, convert someDate to POSIXct will be required.
EDIT: On second thought, months(.) returns a character representation of the month, so that may not be efficient. At least, it'll require a little processing (not too difficult) to give a numeric representation.
R has not implemented these features out of ignorance. difftime objects are transitive. A 700 day difference on any arbitrary start-date can yield a differing number of years depending on whether there was a leap year or not. Similarly for months, they take between 28-31 days.
For research purposes, we use these units a lot (months and years) and pragmatically, we define a year as 365.25 days and a month as 365.25/12 = 30.4375 days.
To do arithmetic on a given difftime, you must convert this value to numeric using as.numeric(difftime.obj) which is, in default, days so R stops spouting off the units.
You can not simply convert a difftime to month, since the definition of months depends on the absolute time at which the difftime has started.
You'll need to know the start date or the end date to accurately tell the number of months.
You could then, e.g., calculate the number of months in the first year of your timespan, the number of month in the last your of the timespan, and add the number of years between times 12.
Hmm. I think the most sensible would be to look at the various units themselves. So compare the day of the month first, then compare the month of the year, then compare the year. At each point, you can introduce a carry to avoid negative values.
In other words, don't work with the product of difftime, but recode your own difftime.

How to calculate day of the week from timestamp? (DST)

I am developing code for device where datetime library is not available (note: floats also unavailable), so I have to do math myslef.
My timestamp is seconds from 1 Jan 2000 (in UTC).
In configuration of device I have:
current timezone as number of hours +/- from UTC
dst as number of hours to add
I need to know:
current day of week
current hour
Calculating current hour is pretty easy:
timestamp % 86400 # seconds from midnight
Calculating day of the week (1-monday,7-sunday):
dayofweek = (timestamp - 86400) % (86400*7) / 86400
if dayofweek = 0:
dayofweek = 7
notes:
86400 = seconds in one day
But before calculations I should:
1. add timezone hours
2. add DST hours
The problem is how to calculate if DST hours (for European Summer Time only) should be added or not? I need to do this efficiently beacuse I have very limited computing power and I need to do this as fast as possible :-)
To determine if DST is applied, you need to know day and month as well. In Europe, the change is on last weekend in March/last weekend in October. Would suggest you apply timezone offset without DST, do your calculations to get hour, day of week, day and month, and then if you are in DST, you may need to adjust any or all of these values (depending on the original value of hour, it may just be hour that needs adjusting).
By doing the timezone offset first, you are getting the local hour/day of week/day values correct without DST, then the DST adjustment is trivial.

ISO 8601 Repeating Interval

Wikipedia gives an example of an ISO 8601 example of a repeating interval:
R5/2008-03-01T13:00:00Z/P1Y2M10DT2H30M
This is what this means:
R5 means that the interval after the slash is repeated 5 times.
2008-03-01T13:00:00Z means that the interval begins at this given datetime.
P1Y2M10DT2H30M means that the interval lasts for
1 year
2 months
10 days
2 hours
30 minutes
My problem is that I do not know exactly what is being repeated here. Does the repetition
occur immediately after the interval ends? Can I specify that every Monday something happens from 13:00 to 14:00?
The standard itself doesn't clarify, but the only obvious interpretation here is that the interval repeats back-to-back. So this recurring interval:
R2/2008-03-01T13:00:00Z/P1Y2M10DT2H30M
Will be equivalent to these non-recurring intervals:
2008-03-01T13:00:00Z/P1Y2M10DT2H30M
2009-05-01T15:30:00Z/P1Y2M10DT2H30M
(Note: my reading is that the number of repetitions does include the first occurrence)
There is no way to represent "every Monday from 13:00 to 14:00" inside of ISO 8601, but it's natural to do for a VEVENT in the iCalendar format. (If you could do that entirely within ISO 8601, then that would give rise to a slew of further feature requests)
Yes, ISO8601 does define a regular repeating interval (or as regular as a "month" can be as one of the units).
R5/2008-03-01T13:00:00Z/P1Y2M10DT2H30M
Should generate these times:
2009-05-11T15:30:00Z
2010-07-21T18:00:00Z
2011-10-01T20:30:00Z
2012-12-11T23:00:00Z
2014-02-22T00:30:00Z
It doesn't define a "start time" and "end time" like RFC5545 (iCalendar) does, or even irregular repetition like RRULE or crontab can.
You should be able to specify a weekly repetition using the ISO Week Date as a starting point, but you'll need separate repetitions for "start" and "end" times:
R/2021-W01-1T13:00:00Z/P1W
R/2021-W01-1T14:00:00Z/P1W
The first interval is for the start times: Mondays at 13:00 (starting in 2021), and the second is for the end times: Mondays at 14:00 (starting in 2021).
I'm probably being an idiot (Long Covid Brain) but isn't the obvious extension to ISO-8601 a second duration part? In the absence of the second duration, the repeats are back to back, in its presence what is actually repeating is a smaller duration event at the start of each period. e.g.
R/2021-W01-1T13:00:00Z/P1W/P1H
indefinite weekly repeat of hour long slots every Monday 1pm starting week 1 2021.
EDIT: Maybe you could even nest them ...
R/2021-W01-1T09:00:00Z/P1W/R5/P1D/P8H
Mon to Fri, 9am to 5pm, every week? Ok I'll get my coat

Resources