clj-time and displaying in user's time zone - datetime

I've been playing around with to-local-date-time, org.joda.time.DateTimeZone/getDefault, formatters, etc. and I still can't figure out how to get a datetime which I've stored as UTC to display in the user's time zone. Some formatters I can get to display the time, but it shows UTC time with an offset. If I have 2013-10-05T19:02:25.641-04:00, for example, how can I get it to display "2013-10-05 14:02:25"?

I think it's better to use build in timezone support from the formatter
(require '[clj-time.core :as t]
'[clj-time.format :as f])
(def custom-time-formatter (f/with-zone (f/formatter "yyyy-MM-dd hh:mm:ss")
(t/default-time-zone)))
(f/unparse custom-time-formatter (t/now))
instead of (t/default-time-zone) you can use a specific timezone or an offset (see clj-time.core documentation)
(maybe that didn't work in 2013 :) )

You can can apply the timezone with clj-time.core/to-time-zone, using clj-time.core/time-zone-for-offset when you only have the target offset, to get the localized time from your stored UTC.
There are numerous existing UTC formatters in the clj-time.format/formatters map, but you can always create your own from clj-time.format/formatter, or clj-time.format/formatter-local, and clj-time.format/unparse.
(require '[clj-time.core :as t]
'[clj-time.format :as f])
(defn formatlocal [n offset]
(let [nlocal (t/to-time-zone n (t/time-zone-for-offset offset))]
(f/unparse (f/formatter-local "yyyy-MM-dd hh:mm:ss aa")
nlocal)))
(formatlocal (t/now) -7)

2013-10-05T19:02:25.641-04:00 is the local time which would be UTC time 2013-10-05T23:02:25.641Z.
If you have a valid UTC time, do not try to convert it with to-local-date-time! to-local-date-time is a convenience function for changing the time zone on a DateTime instance without converting the time. To properly convert the time, use to-time-zone instead.
To format a DateTime without time zone information, use a custom formatter. Your example would be produced by the pattern "yyyy-MM-dd HH:mm:ss".
Example:
Define a UTC time:
time-test.core> (def t0 (date-time 2013 10 05 23 02 25 641))
#'time-test.core/t0
time-test.core> t0
#<DateTime 2013-10-05T23:02:25.641Z>
Convert it to a local time:
time-test.core> (def t1 (to-time-zone t0 (time-zone-for-offset -4)))
#'time-test.core/t1
time-test.core> t1
#<DateTime 2013-10-05T19:02:25.641-04:00>
Format the local time:
time-test.core> (unparse (formatter-local "yyyy-MM-dd HH:mm:ss") t1)
"2013-10-05 19:02:25"

Related

moment-timezone.js get utc offset for a specific date with timezone

I have users entering a date and a time zone (e.g. "America/Los Angeles") for that date and I'd like to convert that to UTC but to do that I need the utc offset for the time on that date.
I can easily convert a date to the offset for the time zone if I already know the UTC date but I need the other way around...
The utc offset can change depending on the date due to daylight saving so I need a way to enter a date and a timezone and get back the offset from UTC using that.
Knowing the most recent switch from PST to PDT On march 11 at 2AM I tried using
var tzOffset = moment.tz("3/11/2018 3:00 AM", "America/Los_Angeles").utcOffset();
document.write('utc offset is : ' + tzOffset + '<br/>') ;
but that gives 480 when the correct answer is 420
I can get the correct answer 420 if I use parseZone like so:
var tzOffset2 = moment.parseZone("3/11/2018 3:00 AM -07:00").utcOffset();
document.write('utc offset2 is : ' + tzOffset2 + '<br/>') ;
but that means I need to already know the -7 offset that I'm trying to find...
So how do I find the utcOffset for a specific date/time like "3/11/2018 3:00 AM" and timezone like "America/Los_Angeles"? Thanks
Your input is not in a ISO 8601 or RFC 2822 format recognized by moment(String), so you have to specify the format as second parameter using moment(String, String) (please note that, as docs states: The moment.tz constructor takes all the same arguments as the moment constructor, but uses the last argument as a time zone identifier.)
Your code could be like the following:
var tzOffset = moment.tz("3/11/2018 3:00 AM", "D/M/YYYY h:mm A", "America/Los_Angeles").utcOffset();
document.write('utc offset is : ' + tzOffset + '<br/>') ;
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.1/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.14/moment-timezone-with-data-2012-2022.min.js"></script>

In Clojure , how do you output a date like this 'Tue, 15-Jan-2013 21:47:38 GMT'?

This date format is used in HTTP Cookie Expires field.
This is my code so far
(ns cookie-handler
(:require[clj-time.format :as f])
(:import (org.joda.time DateTimeZone)))
(def custom-formatter2
(f/formatter "EEE, dd-MMM-yyyy HH:mm:ss zzz" (DateTimeZone/forID "Etc/GMT")))
I invoke this in repl
(f/unparse custom-formatter2 (c/to-date-time (.. (Calendar/getInstance) (getTime) )))
And this is what I get : "Thu, 23-Apr-2015 16:20:22 +00:00"
How do I initialize formatter so that it outputs a date string like "Thu, 23-Apr-2015 16:20:22 GMT"
There is a java version of this issue at java date format - GMT 0700 (PDT)
If all you want is to have GMT at the end of the formatted date string, you can add those characters to the end of the format string
(def custom1 (f/formatter-local "EEE, dd-MMM-yyyy HH:mm:ss 'GMT'"))
(def formatted-date-1 (f/unparse custom1 (t/now)))
"Thu, 23-Apr-2015 19:12:58 GMT"
If you really need GMT followed by the offset, the same idea applies
(def custom2 (f/formatter-local "EEE, dd-MMM-yyyy HH:mm:ss 'GMT'z"))
(def today (t/to-time-zone (t/now) (t/time-zone-for-offset -6)))
(def formatted-date-2 (f/unparse custom-formatter today))
"Thu, 23-Apr-2015 13:12:58 GMT-06:00"
I use the following in a library of mine that needs to output HTTP-spec compliant timestamps:
(def ^:private time-format (f/formatter "EEE, dd MMM yyyy HH:mm:ss"))
(defn- time->str
[time]
(str (f/unparse time-format time) " GMT"))
You can probably include GMT in the format string like G_A suggested, but I haven't tried that.
I do think that using f/formatter rather than f/formatter-local is important though, so that your local timestamp gets converted to UTC before it's converted to a string.

Converting unix timestamp to human readable date and time in clojure

The database query is returning the date and time in a unix timestamp. I am trying to use clojure to convert this into human readable time and then split the date and time into two separate columns under date and time.
Take a look at clj-time
For example here is how you would convert a (long) timestamp to DateTime:
user=> (clj-time.coerce/from-long 893362442345)
#<DateTime 1998-04-23T20:14:02.345Z>
Here is how to "split" it by date/time portions:
user=> (unparse (formatters :date) (clj-time.coerce/from-long 893362442345))
"1998-04-23"
user=> (unparse (formatters :time) (clj-time.coerce/from-long 893362442345))
"20:14:02.345Z"
Depending on how you need the result to be formatted, you can choose from many different built in formatters:
user=> (show-formatters)
:basic-date 20130828
:basic-date-time 20130828T175957.850Z
:basic-date-time-no-ms 20130828T175957Z
:basic-ordinal-date 2013240
:basic-ordinal-date-time 2013240T175957.850Z
:basic-ordinal-date-time-no-ms 2013240T175957Z
:basic-t-time T175957.850Z
:basic-t-time-no-ms T175957Z
:basic-time 175957.850Z
:basic-time-no-ms 175957Z
:basic-week-date 2013W353
:basic-week-date-time 2013W353T175957.850Z
:basic-week-date-time-no-ms 2013W353T175957Z
:date 2013-08-28
:date-hour 2013-08-28T17
:date-hour-minute 2013-08-28T17:59
:date-hour-minute-second 2013-08-28T17:59:57
:date-hour-minute-second-fraction 2013-08-28T17:59:57.850
:date-hour-minute-second-ms 2013-08-28T17:59:57.850
:date-time 2013-08-28T17:59:57.850Z
:date-time-no-ms 2013-08-28T17:59:57Z
:hour 17
:hour-minute 17:59
:hour-minute-second 17:59:57
:hour-minute-second-fraction 17:59:57.850
:hour-minute-second-ms 17:59:57.850
:mysql 2013-08-28 17:59:57
:ordinal-date 2013-240
:ordinal-date-time 2013-240T17:59:57.850Z
:ordinal-date-time-no-ms 2013-240T17:59:57Z
:rfc822 Wed, 28 Aug 2013 17:59:57 +0000
:t-time T17:59:57.850Z
:t-time-no-ms T17:59:57Z
:time 17:59:57.850Z
:time-no-ms 17:59:57Z
:week-date 2013-W35-3
:week-date-time 2013-W35-3T17:59:57.850Z
:week-date-time-no-ms 2013-W35-3T17:59:57Z
:weekyear 2013
:weekyear-week 2013-W35
:weekyear-week-day 2013-W35-3
:year 2013
:year-month 2013-08
:year-month-day 2013-08-28
or built a custom one:
(def custom-formatter (formatter "yyyyMMdd"))

Creating a DateTime object with a specific UTC DateTime in PowerShell

I'm trying to create a DateTime object with a specific UTC timestamp in PowerShell. What's the simplest way to do this?
I tried:
Get-Date
-Format (Get-Culture).DateTimeFormat.UniversalSortableDateTimePattern
-Date "1970-01-01 00:00:00Z"
but I get this output:
1969-12-31 19:00:00Z
It's a few hours off. Where's my lapse in understanding?
The DateTime object itself is being created with the proper UTC time. But when PowerShell prints it out it converts it to my local culture and time zone, thus the difference.
Proof:
$UtcTime = Get-Date -Date "1970-01-01 00:00:00Z"
$UtcTime.ToUniversalTime()
(get-date).ToUniversalTime().ToString("yyyyMMddTHHmmssfffffffZ")
$utctime = New-Object DateTime 1970, 1, 1, 0, 0, 0, ([DateTimeKind]::Utc)
If you print out $utctime, then you get:
1. januar 1970 00:00:00
Also, $utctime.Kind is correctly set to Utc.
$time = [DateTime]::UtcNow | get-date -Format "yyyy-MM-ddTHH:mm:ssZ"
This appears to also work
You can use the SpecifyKind method:
PS C:\IT\s3> $timestamp
Wednesday, July 18, 2018 7:57:14 PM
PS C:\IT\s3> $timestamp.kind
Unspecified
PS C:\IT\s3> $utctimestamp = [DateTime]::SpecifyKind($timestamp,[DateTimeKind]::Utc)
PS C:\IT\s3> $utctimestamp
Wednesday, July 18, 2018 7:57:14 PM
PS C:\IT\s3> $utctimestamp.kind
Utc
This is how it works in .NET, right? PowerShell just calls the ToUniversalTime method. From http://msdn.microsoft.com/en-us/library/system.datetime.touniversaltime.aspx
The Coordinated Universal Time (UTC) is equal to the local time minus the
UTC offset. For more information about the UTC offset, see TimeZone.GetUtcOffset.
The conversion also takes into account the daylight saving time rule that applies
to the time represented by the current DateTime object.

Erlang: timestamp with time zone arithmetics

What is the best way to add/subtract units to/from specific timestamp with respect to time zone in Erlang?
From what I've found, calendar of stdlib can work with either local or UTC time zone, no more. Moreover, arithmetics is recommended to do in UTC time zone only (the reason is obvious).
What should I do if, for instance, I need to add 1 month to {{2011,3,24},{11,13,15}} in, let's say, CET (Central European Time) and local (system) time zone is not CET? That is not even the same as converting this timestamp to UTC, adding 31 * 24 * 60 * 60 seconds and converting back to CET (that will give {{2011,4,24},{12,13,15}} instead of {{2011,4,24},{11,13,15}}). By the way we can't do even such a thing if CET is not local time zone with stdlib.
The answers I found googling are:
setenv to make local time zone = needed time zone (that is very ugly first of all; then it will only allow to convert needed time zone to utc and do arithmetics respective to utc, not the needed time zone)
open_port to linux date util and do arithmetics there (not that ugly; rather slow; needs some parsing, because the protocol between erlang and date will be textual)
port driver or erl_interface to C using its standard library (not ugly at all; but I didn't find ready to use solution and I'm not that good at C to write one)
The ideal solution would be something written in Erlang using OS timezone info, but I didn't find any.
Now I'm stuck to solution 2 (open_port to date util). Is there a better way?
Thanks in advance.
P. S. There was a similar issue, but no good answer there Time zone list issue
port_helper.erl
-module(port_helper).
-export([get_stdout/1]).
get_stdout(Port) ->
loop(Port, []).
loop(Port, DataAcc) ->
receive
{Port, {data, Data}} ->
loop(Port, DataAcc ++ Data);
{Port, eof} ->
DataAcc
end.
timestamp_with_time_zone.erl
-module(timestamp_with_time_zone).
-export([to_time_zone/2, to_universal_time/1, modify/2]).
to_time_zone({{{Year, Month, Day}, {Hour, Minute, Second}}, TimeZone}, OutputTimeZone) ->
InputPattern = "~4.10.0B-~2.10.0B-~2.10.0B ~2.10.0B:~2.10.0B:~2.10.0B",
InputDeep = io_lib:format(InputPattern, [Year, Month, Day, Hour, Minute, Second]),
Input = lists:flatten(InputDeep),
{external_date(Input, TimeZone, OutputTimeZone), OutputTimeZone}.
to_universal_time({{{Year, Month, Day}, {Hour, Minute, Second}}, TimeZone}) ->
{Timestamp, "UTC"} = to_time_zone({{{Year, Month, Day}, {Hour, Minute, Second}}, TimeZone}, "UTC"),
Timestamp.
modify({{{Year, Month, Day}, {Hour, Minute, Second}}, TimeZone}, {Times, Unit}) ->
if
Times > 0 ->
TimesModifier = "";
Times < 0 ->
TimesModifier = " ago"
end,
InputPattern = "~4.10.0B-~2.10.0B-~2.10.0B ~2.10.0B:~2.10.0B:~2.10.0B ~.10B ~s~s",
InputDeep = io_lib:format(InputPattern, [Year, Month, Day, Hour, Minute, Second, abs(Times), Unit, TimesModifier]),
Input = lists:flatten(InputDeep),
external_date(Input, TimeZone, TimeZone).
external_date(Input, InputTimeZone, OutputTimeZone) ->
CmdPattern = "date --date 'TZ=\"~s\" ~s' +%Y%m%d%H%M%S",
CmdDeep = io_lib:format(CmdPattern, [InputTimeZone, Input]),
Cmd = lists:flatten(CmdDeep),
Port = open_port({spawn, Cmd}, [{env, [{"TZ", OutputTimeZone}]}, eof, stderr_to_stdout]),
ResultString = port_helper:get_stdout(Port),
case io_lib:fread("~4d~2d~2d~2d~2d~2d", ResultString) of
{ok, [YearNew, MonthNew, DayNew, HourNew, MinuteNew, SecondNew], _LeftOverChars} ->
{{YearNew, MonthNew, DayNew}, {HourNew, MinuteNew, SecondNew}}
end.

Resources