Switch between dates and seconds in a well defined manner - r

I run discrete event simulations where the time originates from dates. I think that simulations run much faster, when I convert all the dates to integers (relative time in seconds).
What is the best way, to switch between date and seconds in a well definied way where I want to
set the reference time (e.g. "1970-01-01 00:00:00 GMT" or "2016-01-01 00:00:00 GMT") manually,
the time zone and
the origin (Not possible in lubridate?)
I thought I can use the origin for this purpose but it does not influence the result:
> as.numeric(as.POSIXct("2016-01-01 00:00:00 GMT",origin="2016-01-01",tz="GMT"))
> as.numeric(as.POSIXct("2016-01-01 00:00:00 GMT",origin="1970-01-01",tz="GMT"))
both result in [1] 1451606400.
(Only the tz argument changes the result, which is ok of course:
> as.numeric(as.POSIXct("2016-01-01 00:00:00 CEST", tz= "America/Chicago"))
[1] 1451628000)

You can use difftime() to calculate the difference between some timestamp and a reference time:
as.numeric(difftime(as.POSIXct("2016-01-01 00:00:00",tz="GMT"),
as.POSIXct("1970-01-01 00:00:00",tz="GMT"), units = "secs"))
## [1] 1451606400
By choosing another value for units, you could also get the number of minutes, hours, etc.
The reason that you get the same result for both choices of origin is that this argument is only intended to be used when converting a number into a date. Then, the number is interpreted as seconds since the origin that you pass to the function.
Internally, a POSIXct object is always stored as seconds since 1970-01-01 00:00:00, UTC, independent of the origin that you specified when doing the conversion. And accordingly, converting to numeric gives the same result for any choice of origin.
You can have a look at the documentation of as.POSIXct():
## S3 method for class 'character'
as.POSIXlt(x, tz = "", format, ...)
## S3 method for class 'numeric'
as.POSIXlt(x, tz = "", origin, ...)
As you can see, origin is only an argument for the method for numeric, but not for character.

Related

How to convert matlab numeric to POSIXct [duplicate]

I have some MATLAB serial date number that I need to use in R but I havt to convert them to a normal date.
Matlab:
datestr(733038.6)
ans =
27-Dec-2006 14:24:00
you can see it gives the date and time.
Now we try in R:
Matlab2Rdate <- function(val) as.Date(val - 1, origin = '0000-01-01')
> Matlab2Rdate(733038.6)
[1] "2006-12-27"
It gives only the date but I need also the time? Any idea
The trick is Matlab uses "January 01, 0000", a fictional reference date, to calculate its date number. The origin of time for the "POSIXct" class in R is, ‘1970-01-01 00:00.00 UTC’. You can read about how different systems handle dates here.
Before converting, you need to account for this difference in reference from one format to another. The POSIX manual contains such an example. Here's my output:
> val<-733038.6
> as.POSIXct((val - 719529)*86400, origin = "1970-01-01", tz = "UTC")
[1] "2006-12-27 14:23:59 UTC"
Where 719529 is ‘1970-01-01 00:00.00 UTC’ in Matlab's datenum and 86400 the number of seconds in an standard UTC day.

How to convert from CEST to UTC?

I want to convert number of days to date with time:
> 15525.1+as.Date("1970-01-01")
[1] "2012-07-04" ## correct but no time
I tried this:
> apollo.fmt <- "%B %d, %Y, %H:%M:%S"
> as.POSIXct((15525.1+as.Date("1970-01-01")), format=apollo.fmt, tz="UTC")
[1] "2012-07-04 04:24:00 CEST"
but as you see the results provide in CEST. But I need it it in UTC.
Any hints on this?
For the original conversion, refer to this question: Converting numeric time to datetime POSIXct format in R and these pages: Date-times in R , Date-time conversions and Converting excel dates (number) to R date-time object. Bascially, it depends on your data source, the time origin for that data sources (Excel, Apache etc.) and the units. For example, you may have the total time elapsed in seconds, minutes, hours or days since the time origin for your data source which will be different for Excel or Apache. Once you have this information, you can use strptime or origin arguments and convert to R date-time objects.
If you are only concerned with changing the timezone, you can use attr:
> u <- Sys.time()
> u
[1] "2017-12-21 09:01:35 EST"
> attr(u, "tzone") <- "UTC"
> u
[1] "2017-12-21 14:01:35 UTC"
You may want to check up on the valid timezones for your machine though. A good way to get a time-zone that works with your machine would be googleway::google_timezone. To get the coordinates for your location (or the location from where you're importing data), you can either look those up online or use ggmap::geocode() - useful if converting time stamps in data from different time zones.
I think the problem is as.POSIXct doesn't change anything if the time is already POSIXct, so the tz option has no effect.
Use attr as explained here

R: Posix (Unix) Time Crazy Conversion

Unix time is 1435617000.
as.Date(1435617000,origin="01-01-1970")
[1] "3930586-11-23"
Which is wrong. I'm trying to (a) get the correct date, which, per epoch converter is GMT: Mon, 29 Jun 2015 22:30:00 GMT.
How do I get R to tell me the month, day, year, hour, minute & second? Thank you.
I think the reason why that happen is because as.Date converts arguments to class date objects. In this case you do not need a date but a class POSIXct object because your input, the x vector, contains other informations that as.Date is not able to manage. Another problem that even with the right function could appear, is that if when you do not specify the right time zone with the tz argument (except the case where your time zone is the same as the original time).
The following code does the job.
x <- 1435617000
as.POSIXct(x, origin = "1970-01-01", tz ="GMT")
[1] "2015-06-29 22:30:00 GMT"
Use as.Date
Just in the case you wanted only the date but you have a complete Unix time like x, you have to just divide by 86400 (which is the number of seconds in a day!) to get only the right date.
as.Date(x/86400L, origin = "1970-01-01")
[1] "2015-06-29"
Another important detail
The origin argument has to be supplied with YYYY-MM-DD and not like you did DD-MM-YYYY I am not sure but I think that the former is the only accepted and correct way.

as.POSIXct assigns different timezones [duplicate]

I am trying to convert UTC time to local standard time. I have found many functions which convert to Local Daylight Time, but I was not successful in getting the standard time. Right now, I have the following code which converts to local daylight time at my specific timezone:
pb.date <- as.POSIXct(date,tz="UTC")
format(pb.date, tz="timeZone",usetz=TRUE)
I would appreciate any help.
First, POSIXct date-times are always UCT internally. The print.POSIXt and format.POSIXt methods will appropriately make the TZ shift on output from their internal representations:
pb.date <- as.POSIXct(Sys.Date())
Sys.Date()
#[1] "2015-07-09"
So that was midnight of the current date in Greenwich:
format(pb.date, tz="America/Los_Angeles",usetz=TRUE)
#[1] "2015-07-08 17:00:00 PDT"
When it's midnight in Greenwich, it's 5PM Daylight Time in the previous day on the Left Coast of the US. You need to use the correct character values for your TZ (and your OS) both of which at the moment are unspecified.
The US Pacific timezone is 8 hours behind GMT (in winter months) so you can use a timezone that is Standard/Daylight-agnostic:
> format(pb.date,usetz=TRUE, tz="Etc/GMT+8")
[1] "2015-07-08 16:00:00 GMT+8"
(Notice the reversal of + with "behind" and - with "ahead".)
I know this question has an accepted answer, but in case anyone comes along and this can help. I needed a function to convert UTC times to MTN time (Server is in UTC, we operate in MTN).
Not sure why, but needed to force it to UTC/GMT first and the convert it to MTN. However it does work
mtn_ts = function(utcTime){
library(lubridate)
toTz = "us/mountain"
utcTime = force_tz(utcTime,tzone= 'GMT')
dt = as.POSIXct(format(utcTime,tz = toTz,origin ='GMT', usetz=TRUE))
dt = force_tz(dt,tzone= toTz)
return(dt)
}
mtn_ts(as.POSIXct("2021-09-27 14:48:51.000000000"))

How to add/subtract time from a POSIXlt time while keeping its class in R?

I am manipulating some POSIXlt DateTime objects. For example I would like to add an hour:
my.lt = as.POSIXlt("2010-01-09 22:00:00")
new.lt = my.lt + 3600
new.lt
# [1] "2010-01-09 23:00:00 EST"
class(new.lt)
# [1] "POSIXct" "POSIXt"
The thing is I want new.lt to be a POSIXlt object. I know I could use as.POSIXlt to convert it back to POSIXlt, but is there a more elegant and efficient way to achieve this?
POSIXct-classed objects are internally a numeric value that allows numeric calculations. POSIXlt-objects are internally lists. Unfortunately for your desires, Ops.POSIXt (which is what is called when you use "+") coerces to POSIXct with this code:
if (inherits(e1, "POSIXlt") || is.character(e1))
e1 <- as.POSIXct(e1)
Fortunately, if you just want to and an hour there is a handy alternative to adding 3600. Instead use the list structure and add 1 to the hour element:
> my.lt$hour <- my.lt$hour +1
> my.lt
[1] "2010-01-09 23:00:00"
This approach is very handy when you want to avoid thorny questions about DST changes, at least if you want adding days to give you the same time-of-day.
Edit (adding #sunt's code demonstrating that Ops.POSIXlt is careful with time "overflow".))
my.lt = as.POSIXlt("2010-01-09 23:05:00")
my.lt$hour=my.lt$hour+1
my.lt
# [1] "2010-01-10 00:05:00"
Short answer: No
Long answer:
POSIXct and POSIXlt objects are two specific types of the more general POSIXt class (not in a strictly object oriented inheritance sense, but in a quasi-object oriented implementation sense). Code freely switches between these. When you add to a POSIXlt object, the actual function used is +.POSIXt, not one specifically for POSIXlt. Inside this function, the argument is converted into a POSIXct and then dealt with (added to).
Additionally, POSIXct is the number of seconds from a specific date and time. POSIXlt is a list of date parts (seconds, minutes, hours, day of month, month, year, day of week, day of year, DST info) so adding to that directly doesn't make any sense. Converting it to a number of seconds (POSIXct) and adding to that does make sense.
It may not be significantly more elegant, but
seq.POSIXt( from=Sys.time(), by="1 hour", length.out=2 )[2]
IMHO is more descriptive than
Sys.time()+3600; # 60 minutes * 60 seconds
because the code itself documents that you're going for a "POSIX" "seq"uence incremented "by 1 hour", but it's a matter of taste. Works just fine on POSIXlt, but note that it returns a POSIXct either way. Also works for "days". See help(seq.POSIXt) for details on how it handles months, daylight savings, etc.
?POSIXlt tells you that:
Any conversion that needs to go between the two date-time classes requires a timezone: conversion from "POSIXlt" to "POSIXct" will validate times in the selected timezone.
So I guess that 3600 not being a POSIXlt object, there is an automatic conversion.
I would stick with simple:
new.lt = as.POSIXlt(my.lt + 3600)
class(new.lt)
[1] "POSIXlt" "POSIXt"
It's not that much of a hassle to add as.POSIXlt before your time operation.

Resources