Convert durations in Ruby - hh:mm:ss.sss to milliseconds and vice versa
How about this?
a=[1, 1000, 60000, 3600000]*2
ms="01:45:36.180".split(/[:\.]/).map{|time| time.to_i*a.pop}.inject(&:+)
# => 6336180
t = "%02d" % (ms / a[3]).to_s << ":" <<
"%02d" % (ms % a[3] / a[2]).to_s << ":" <<
"%02d" % (ms % a[2] / a[1]).to_s << "." <<
"%03d" % (ms % a[1]).to_s
# => "01:45:36.180"
What is the proper way to form Rails data before I store it in my Postgres interval data-type column?
You are correct in using the interval
type for saving hours, minutes and seconds. But this will not save the milliseconds.
What you did was converting a time into milliseconds. Your interval field only knows of seconds, and 6_000_000
seconds resulted in 16666:40:0
- exceeding the 1_000_000
seconds it represents, which seems to be the max limit.
You should approach this differently:
Use the interval
field as intended: save hours, minutes, and seconds into a column - they are part of your form anyway. Then it will be easy to display it in the view as well.
Then, if you want to retrieve your milliseconds, simply add a method:
class Bar < ActiveRecord::Base
def time_in_milliseconds
# retrieve the interval seconds from the database and multiply by 1000
end
end
Also, for handling the conversion of milliseconds to hh:mm:ss
format and back you should check out this great answer. Hive: Convert string datetime with missing seconds in yyyy-MM-dd'T'HH:mm:ss.SSS'Z'
from_unixtime
is always until minutes(yyyy-MM-dd HH:mm:ss)
to get millisecs
we need to do some workarounds.
- we will extract the
millisecs
from the old_time usingregexp_extract
thenconcat
that tofrom_unixtime
result and finally cast totimestamp
.
Example:
select old_time,
timestamp(concat_ws(".", --concat_ws with . and cast
FROM_UNIXTIME(UNIX_TIMESTAMP(old_time, "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"),"yyyy-MM-dd HH:mm:ss"), -- from_unixtime and unix_timestamp to convert without millisecs
regexp_extract(string(old_time),".+\\.(.*)(?i)z",1))) as newtime from --regexp_extract to extract last 3 digits before z then concat
(select string("2020-03-11T21:14:41.335Z")old_time)e
+------------------------+-----------------------+
|old_time |newtime |
+------------------------+-----------------------+
|2020-03-11T21:14:41.335Z|2020-03-11 21:14:41.335|
+------------------------+-----------------------+
UPDATE:
Your sample data have :
before milliseconds, Try with below query:
select old_time,
timestamp(concat_ws(".", --concat_ws with . and cast
FROM_UNIXTIME(UNIX_TIMESTAMP(old_time, "yyyy-MM-dd'T'HH:mm:ss:SSS'Z'"),"yyyy-MM-dd HH:mm:ss"), -- from_unixtime and unix_timestamp to convert without millisecs
regexp_extract(string(old_time),".+\\:(.*)(?i)z",1))) as newtime from --regexp_extract to extract last 3 digits before z then concat
(select string("2020-03-11T21:14:41:335Z")old_time)e
Convert Sqlite Unix Epoch in milliseconds to Datetime YYYY-MM-DD HH:MM:SS.SSS
All date functions accept the same date formats and modifiers, so you can simply remove the nested datetime
call.
And you need to do a floating-point division to preserve the milliseconds:
SELECT strftime('%d-%m-%Y %H:%M:%f', time/1000.0, 'unixepoch') FROM table1;
How I can convert DateTime.now in C# to yyyy-mm-dd hh:mm:ss.sssssss?
I suspect if you really need the string representation, you actually want:
string text = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.fffffff",
CultureInfo.InvariantCulture)
Note that:- Unless you really want the local time, use
UtcNow
instead ofNow
. For timestamps, you almost always want UTC. - I doubt that you want to use the time separator of the current culture, hence the specification of
CultureInfo.InvariantCulture
- "MM" means months whereas "mm" means minutes
- "HH" means 24-hour clock whereas "hh" means 12-hour clock
- "ff..." is used for fractions of a second
However, I'd strongly recommend that you try to avoid string conversions wherever possible. Why can't your stored procedure just use the relevant DateTime
type instead of a string representation? Then you can pass the value to the stored procedure as a DateTime
(via a command parameter) and you can get rid of the error-prone string conversion clutter.
DateTime Conversion to Unix Epoch Adding Phantom Hour
A few things:
If possible, you should work with
DateTimeOffset
instead ofDateTime
for this type of operation.DateTimeOffset
is always a specific moment in time, whileDateTime
might be, or might not be, depending onKind
and how well you adhere to the subtleties of howKind
is interpreted by various methods.If you do use
DateTimeOffset
, and you are targeting .NET 4.6 or greater (or .NET Core), then you can use the built inDateTimeOffset.FromUnixTimeMilliseconds
andToUnixTimeMilliseconds
methods, rather than creating your own.You might consider using the Noda Time open source library, as it adds significant value to most applications working with date and time.
- For instance, if you want to work with tzdb time zones like the
"Europe/London"
zone you mentioned, then you can useDateTimeZoneProviders.Tzdb["Europe/London"]
.
- For instance, if you want to work with tzdb time zones like the
You have
UnixEpoch
implemented as a static method. Since its value never changes, it should probably be implemented as a static property, with a private readonly backing field. It could also be implemented as a public static readonly field, though most people prefer exposing those via properties. (These are just coding guidelines, but don't introduce any error.)In your
FromMillisecondsSinceUnixEpoch
method, you are calling.ToLocalTime()
. That should be omitted. You don't need to call.ToUniversalTime()
either. Just return the result of adding the milliseconds. TheKind
will beUtc
. If you need to work with local time, do the conversion later - not inside this function.Recognize that the ID
"GMT Standard Time"
is for London, not UTC. London is either GMT (UTC+00:00) or BST (UTC+01:00) depending on the date and time in question.Recognize that
DateTime.ToLocalTime
andDateTime.ToUniversalTime
convert between UTC and the current local time zone on the machine where the code is running. That might be London, or might be something else depending on your use case. If you're running on a server, such as in an ASP.Net web application, then it's not a good practice to rely on the system local time zone.In the code you showed with
TimeZoneInfo.ConvertTime
, since you didn't assignDateTimeKind.Utc
to the input, that value will haveDateTimeKind.Unspecified
.ConvertTime
will interpret that as already belonging to the source time zone. Since you've given the same destination time zone, then in most cases this will be a no-op.In that same function, it's invalid to define
unixEpoch
in terms of London time, for the reasons specified earlier. Also note that on 1970-01-01, London was not on GMT, but actually on BST (known as "British Standard Time" back then, rather than "British Summer time"). TZDB knows about this, but it's too far back for Windows time zones andTimeZoneInfo
. The"GMT Standard Time"
Windows zone only reflects the current rules around BST/GMT, not those that were in effect at the time.
.Net 3.5+
public static long UkTimeStringToUtcMillis(string s)
{
string format = "yyyy-MM-dd'T'HH:mm:ss.FFF";
DateTime dt = DateTime.ParseExact(s, format, CultureInfo.InvariantCulture);
TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
DateTime utc = TimeZoneInfo.ConvertTimeToUtc(dt, tz);
DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
return (long) (utc - epoch).TotalMilliseconds;
}.Net 4.6+ / .Net CoreCLR
public static long UkTimeStringToUtcMillis(string s)
{
string format = "yyyy-MM-dd'T'HH:mm:ss.FFF";
DateTime dt = DateTime.ParseExact(s, format, CultureInfo.InvariantCulture);
TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
TimeSpan offset = tz.GetUtcOffset(dt);
DateTimeOffset dto = new DateTimeOffset(dt, offset);
return dto.ToUnixTimeMilliseconds();
}Noda Time
public static long UkTimeStringToUtcMillis(string s)
{
LocalDateTimePattern pattern = LocalDateTimePattern.ExtendedIsoPattern;
LocalDateTime dt = pattern.Parse(s).Value;
DateTimeZone tz = DateTimeZoneProviders.Tzdb["Europe/London"];
Instant i = dt.InZoneLeniently(tz).ToInstant();
return i.Ticks / NodaConstants.TicksPerMillisecond;
}
Change yyyy-mm-ddThh-mm-ss to datetime, throw away T separator and milliseconds
For example:
import time
print time.strftime("%Y-%m-%d %H:%M:%S")
# 2018-06-28 08:00:35
As to your question:import datetime
str_time = '2018-03-08T08:00:00.000'
d = datetime.datetime.strptime(str_time, "%Y-%m-%dT%H:%M:%S.%f")
print d
# 2018-03-08 08:00:00
New method:import time
str_time = '2018-03-08T08:00:00.000'
d = time.strptime(str_time, "%Y-%m-%dT%H:%M:%S.%f")
print d
# time.struct_time(tm_year=2018, tm_mon=3, tm_mday=8, tm_hour=8, tm_min=0, tm_sec=0, tm_wday=3, tm_yday=67, tm_isdst=-1)
print time.strftime("%Y-%m-%d %H:%M:%S", d)
# 2018-03-08 08:00:00
Related Topics
Error Installing Ruby in Yosemite
Sqlite3::Sqlexception: Duplicate Column Name While Migrating
Rails 4 - Devise: Getting Actioncontroller::Unknownformat on Signup
Persistent Tcp Connection in Rails App
Ruby Datamapper Table Inheritance with Associations
How to Unescape C-Style Escape Sequences from Ruby
Ruby: How to Escape Url with Square Brackets [ and ]
Timeout When Installing Ruby Gems
Rails3 Activerecord::Statementinvalid:... No Such Table in Every Test