Ruby- get date from microseconds - ruby

Alright I was looking at this in python but I just like ruby better. What I'm trying to do is get a date and time from this number - 12988822998637849 - which is the number of microseconds since January 1, 1601 UTC. This is how Chrome stores it's timestamps and i've seen a number of methods to do this in python, but I am just more comfortable with ruby and I have no idea on how to even start going about doing this. (My Google-Fu didn't help me this time)
Note this example number is from a few days ago. I'll take any help I can get. Thank you!

look at Time.at.
A Windows file time is "a 64-bit value that represents the number of 100-nanosecond intervals that have elapsed since 12:00 midnight, January 1, 1601 A.D. (C.E.) Coordinated Universal Time (UTC)." Ref.
In contrast, Ruby stores times like Unix: "Time is stored internally as the number of seconds and microseconds since the epoch, January 1, 1970 00:00 UTC" Ref.
# This return a Time
Time.at(12988822998637849/1000000-11644473600) # Epoch Diff is 11644473600
# => 2012-08-07 11:23:18 -0300
# This returns a String
Time.at(12988822998637849/1000000-11644473600).strftime("%Y-%m-%d %H:%M.%S")
# => "2012-08-07 11:23.18"

All you need to do is to create a Ruby date using the Chrome time origin, then increment by the requisite number of microseconds:
Time.gm(1601,1,1) + 12988822998637849 / 1000000
# => 2012-08-07 14:23:18 UTC

Related

Is there a one to one and onto relation between ISO-8601 UTC and Unix Timestamp?

Time Formats
A point in time is often represented as Unix Time, or as a human-readable ISO 8601 date in UTC time string.
For example:
Unix Time
Seconds since Epoch, or Unix timestamp, in seconds or milliseconds:
1529325705
1529325705000
ISO 8601 Date
2018-06-18T15:41:45+00:00
My question
Is there a one-to-one and onto relationship between the two? In other words, is there a point in time with a single representation in one format, and more than one, or zero, representations in the other?
Yes, it is possible to find such a date. From the wiki article on Unix time:
Every day is treated as if it contains exactly 86400 seconds,[2] so leap seconds are not applied to seconds since the Epoch.
That means that the leap seconds themselves cannot be represented in Unix time.
For example, the latest leap second occurred at the end of 2016, so 2016-12-31T23:59:60+00:00 is a valid ISO 8601 time stamp. However, the Unix time stamp for the second before, at 23:59:59, is represented as 1483228799 and the second after, 00:00:00 (on January 1 2017) is 1483228800, so there is no Unix timestamp that represents the leap second.
In practice, this is probably not a problem for you; there has only been 27 leap seconds since they were introduced in 1972.
It might be worthwhile to mention that most software implementations of ISO 8601 does not take leap seconds into account either, but will do something else if asked to parse "2016-12-31T23:59:60+00:00". The System.DateTime class in .NET throws an exception, while it's also conceivable that a library would return 2017-01-01 00:00:00.
No. there is a nice correspondence between the two, but the relationship is 1 to many, and strictly speaking there may not even exist a precise Unix millisecond for a given ISO date-time string. Some issues are:
There are some freedoms in the ISO 8601 format, so the same Unix millisecond may be written in several ways even when we require that the time be in UTC (the offset is zero).
Seconds and fraction of seconds are optional, and there may be a varying number of decimals on the seconds. So a milliseconds value of 1 529 381 160 000, for example, could be written as for example
2018-06-19T04:06:00.000000000Z
2018-06-19T04:06:00.00Z
2018-06-19T04:06:00Z
2018-06-19T04:06Z
The offset of 0 would normally be written as Z, but may also be written as you do in the question, +00:00. I think the forms +00 and +0000 are OK too (forms with a minus are not).
Since there may be more than three decimals on the seconds in ISO 8601, no exact Unix millisecond may match. So you will have to accept truncation (or rounding) to convert to Unix time. Of course the error will be still greater if you convert to Unix seconds rather than milliseconds.
As Thomas Lycken noted, leap seconds can be represented in ISO 8601, but not in Unix time.
In other words, is there a point in time with a single representation in one format, and more than one, or zero, representations in the other?
No. The UTC time depends on your geographic location, ie. your latitude and longitude. However, the UNIX timestamp is a way to track time as a running total of seconds. This count starts at the Unix Epoch on January 1st, 1970 at UTC.
From Unix TimeStamp,
It should also be pointed out that this point in time technically does not change no
matter where you are located on the globe.

Timezone confusion with Ruby's Time class

It's worth noting I am using Ruby 2.1.2, and so the Time class uses a signed 63 bit integer. The integer is used when it can represent a number of nanoseconds since the Epoch; otherwise, bignum or rational is used, according to the documentation.
When I use ::new without arguments, it gives me the current time using my local time zone (not UTC):
> Time.new
=> 2015-06-30 18:29:08 -0400
It's correct. It's 6:29pm on the East coast of the US. Now I want to check the local time in two timezones to the east of EDT:
> t = Time.new(2015,6,30,18,29,8,"+02:00")
=> 2015-06-30 18:29:08 +0200
This is where my confusion comes in. When I specify two timezones to the east of me, I expect there to be two additional hours because each timezone is 15 degrees longitude and each is represented by 1 hour.
Why did it give me the same time as my local time, instead of two hours later?
What you think is happening isn't what's happening. What you've done is give that time an offset of GMT +2 as opposed to two hours out from your current timezone.
If you want to see the time at the offset of two hours ahead of where you are, then you want to create the instance of Time, get your local time, and shift that by the GMT offset.
Time.now.getlocal("-02:00")
If you want to compute this, you have to look at your local time's utc_offset first, then either add or subtract the product of 3600 and however many timezones you want to move. Note that this only moves timezones in whole number increments and will break in cases where a timezone that requires a different precision is needed (i.e. Newfoundland).
t = Time.now
t.getlocal(t.utc_offset + (3600 * 2))

Library method for seconds elapsed since start of year

I want to calculate the number of seconds elapsed since the start of the current year. A straightforward approach would be to get the current date and the date on the start of the year and subtract the two but I was wondering if there was a library method that could do that for me.
This would help my year to date calculations look prettier.
current_time = Time.new
current_time - Time.new(current_time.year)
This will return a Float of the number of seconds since the start of the current year. See Time for more information.

Unknown timestamp reference date

I'm currently dealing with a system which uses an unknown timestamp mechanism.
The system is running on a Windows machine, so my first thought was that it uses some kind of Windows epoch for its timestamps, but it appears it does not.
My goal is to convert these timestamps to Unix timestamps.
A few examples:
The following timestamp: 2111441659 converts to: 2013-10-01 11:59
2111441998 to 2013-10-01 17:14
2111443876 to 2013-10-02 14:36
2111444089 to 2013-10-02 17:57
(All dates are GMT+2)
I've tried to calculate the reference date using the data above, but somehow I get a different result with every single timestamp.
Could anybody shed some light on this rather odd problem?
Thanks in advance!
To me the number seems to small to be milliseconds. My first guess was then seconds but looking at the speed this number varies with i think minutes is a better guess. Doing some math on it 2111441659/60/24/365 = 4017.20254756 which suggests the epoch might be sometime in the year -2000?
Here is a list of common epochs in computing but the year -2000 is not really there :) How are you obtaining this timestamp?
P.S. are you sure the year is set to 2013 on this machine and not to 4013? :) This would then fit with the .NET epoch of January 1, Year 1
In order to distinguish your timestamp from Unix timestamp, let's call yours The Counter.
So we have four counter values with their corresponding DateTime value. The first thing to do is calculate the counter's unit correspondence to a real time unit, let's say a second.
In order to do that, we need (1) the difference d between two counter values and (2) the difference s between their corresponding DateTimes, in seconds.
Considering the first two values we have d1=2111441998-2111441659=339. The difference between 2013-10-01 11:59 and 2013-10-01 17:14 (in seconds) is s1=18900. Consequently, the counter's unit corresponds to u1=s1/d1=55.7522123894 seconds.
But if we do the same with pairs #2 and #3, we will find that u2=40.9584664536 seconds.
Similarily, pairs #3 and #4 give us u3=56.6197183114 seconds.
My conclusion therefore, is that there's no alignment between the counter values and the corresponding DateTimes provided. That's the reason why you get a different result with each sample.
Finally, after many hours of comparing the timestamps with the datetimes, trying to discover the logic between them, I've found the answer by reverse engineering the software which generates the timestamps.
It turns out that the integer timestamps are actually bitwise representations* of the datetimes.
In pseudocode:
year = TimeStamp >> 20;
month = (TimeStamp >> 16) & 15;
day = (TimeStamp >> 11) & 31;
hour = (TimeStamp >> 6) & 31;
minute = TimeStamp & 63;
*I'm not sure if this is the correct term for it, if not, please correct me.

gps time, time conversion

I have time in UTC seconds format. Could any one assist on how to convert such numbers to GPS
time in normal timestamp (dd-mm-yyyy hh:mm:ss)? I need a C code or, perhaps, algorithm.
Update (June 2017): Currently 18 leap seconds.
GPS time is simply UTC time, but without leap seconds. As of this writing, there have been 15 leap seconds since the GPS epoch (January 6, 1980 # 00:00:00), so if it's 2012/02/13 # 12:00:00 (UTC), then it's 2012/02/13 # 12:00:15 in GPS time. If you want to do correct conversions for other times, you'll have to take into account when each leap second went into effect.
Here's how you can compute the current offset, from a couple different "authoritative" sources:
http://www.ietf.org/timezones/data/leap-seconds.list -- Count the number of lines starting from the 2571782400 20 # 1 Jul 1981 line. Or just subtract 19 from the last number in the list (e.g., 37-19 = 18) as of May 2017.
https://www.nist.gov/pml/time-and-frequency-division/atomic-standards/leap-second-and-ut1-utc-information -- Count the number of leap seconds inserted (from the Leap Seconds Inserted into the UTC Time Scale section), starting with (and including) the 1981-06-30 entry.
There is a Javascript library that can convert to and from unixtime. The library is available at
http://www.lsc-group.phys.uwm.edu/~kline/gpstime/
Whatever algorithm you use, you must update it when new leap seconds are announced.
for an algorithm check this site source code: UTC Converter
for built-in functions in c++ check here - especially ctime()

Resources