I have a HTML form which has a date and time field. I assume that when a user enters a date/time, they are doing so in their local time, but when I store it in the database, I need it in UTC, and then when displaying it I need to adjust it to the viewers time.
Can I know the clients timezone from the server (I am using PHP and Apache, but may use IIS in the future, so would rather not rely on Apache-only behavior if possible)? Or can I do UTC <-> Local conversions on the client in Javascript?
Example:
A user in UTC+1 timezone submits 2012-10-18 01:30. This should get stored as the timestamp of 2012-10-18 00:30:00 (whatever that is). Then, if a client at UTC-5 with local DST views the record, they should see 2012-10-17 20:30.
<html>
<head>
<script>
function test()
{
var d = new Date(2012, 6, 13, 12, 0, 0, 0);
console.log(d);
var hours = d.getUTCHours();
console.log(hours);
}
</script>
</head>
<body>
<input type="button" onclick="test()" value="test"/>
</body>
</html>
You input d as local time, and get UTC time by using getUTCHours(), getUTCDates(), etc...
Then send UTC time back to server.
Related
Assume having a Eloquent model called Request with the column next_check autocasted as date (protected $dates = ['next_check'];).
APP_TIMEZONE is initial Europe/Helsinki (+02:00)
$ artisan tinker
Psy Shell v0.10.4 (PHP 7.4.11 — cli) by Justin Hileman
>>> $pr = Request::find(1);
>>> $pr->next_check = Carbon\Carbon::now();
>>> $pr->save();
>>> Request::find(1)->next_check;
=> Illuminate\Support\Carbon #1603973824 {#2900
date: 2020-10-29 14:17:04.0 Europe/Helsinki (+02:00),
}
That looks all fine and we saved 14:17:04 assuming we're in Helsinki.
Now changing the timezone to Europe/Berlin (+01:00), I would assume to get 13:17:04 returned.
>>> Request::find(1)->next_check;
=> Illuminate\Support\Carbon #1603977424 {#2900
date: 2020-10-29 14:17:04.0 Europe/Berlin (+01:00),
}
The timezone is changed but still there is the time returned, which was originally saved in Europe/Helsinki time.
Is that an expected behaviour and how can I get my desired behaviour that a change of the app timezone would result in converted times?
p.s.: the db timezone configured in laravel is still the default '+00:00'
If you want to localise times so they show to user in the user's timezone, you need to CONVERT an existing datetime:
$users_timezone = 'Europe/Berlin';
$datetime->setTimezone($users_timezone);
This will actually change the time according to the difference between the app's timezone and the one converted to.
To get my expected behaviour, I now found a solution. If anybody else want's that exact same behaviour, this might be the solution:
Add the following call in your AppServiceProvider's boot-method:
$this->setUTCOffsetInDBConnection();
The setUTCOffsetInDBConnection method's code is as following:
// according to https://www.sitepoint.com/synchronize-php-mysql-timezone-configuration/
private function setUTCOffsetInDBConnection() {
$now = new \DateTime();
$mins = $now->getOffset() / 60;
$sgn = ($mins < 0 ? -1 : 1);
$mins = abs($mins);
$hrs = floor($mins / 60);
$mins -= $hrs * 60;
$offset = sprintf('%+d:%02d', $hrs*$sgn, $mins);
DB::statement("SET time_zone='".$offset."';");
}
This will always synchronize the timezone according to your app's timezone and save the timestamps as UTC in the database.
When you now save a timestamp 2020-10-29 15:28:00 from your app with APP_TIMEZONE=Europe/Berlin in your .env, it will save it as UTC in the database (2020-10-29 15:28:00).
When you change your APP_TIMEZONE to Europe/Helsinki now, you will get 2020-10-29 16:28:00 returned.
Be aware that your phpMyAdmin might still not show the saved UTC times in your database since also phpMyAdmin sets the servers timezone when opening the connection. So if your server which runs phpMyAdmin is also in Europe/Berlin, you will see 2020-10-29 15:28:00 and not the UTC date saved in the DB.
Answer to "Is that an expected behaviour" is YES
To "save" the timezone with the date data, you have to save it too as an extra column.
So having both "2020-10-29 14:17:04.0" and "Europe/Helsinki" in DB will allow you to remember what timezone was used to save this date, so if it's changed, you can convert.
But first you should consider not to change your app and DB timezone, both should remain UTC.
See https://medium.com/#kylekatarnls/always-use-utc-dates-and-times-8a8200ca3164
So so you can easily convert them into any timezone and display it properly according to the user timezone while keeping a standard well-known format in DB.
This is a Xamarin Forms app.
In some part of the code, I am transfering an object to a Web Api 2 service.
The object is serialized using this:
var json = JsonConvert.SerializeObject(new
{
item.Codigo,
registro.Fecha,
Latitud = registro.Posicion.Latitude,
Longitud = registro.Posicion.Longitude,
Altitud = registro.Posicion.Altitude
});
Where registro.Fecha contains a date and time.
If that variable is, for example, 25th July 2019 at 07:02 P.M.
The date and time is serialized this way:
2019-07-25T19:02:09.53052+08:00
How can I get rid of that "+08:00"? That causes the Web Api application store the data as 25th July 2019 at 07:02 A.M.. My country is at UTC-4. I think that is why the server store the data with +12 hours in difference.
When using a REST tester, I pass the parameter without the "+08:00" and it works.
How can I solve this?
I tried by adding
var userSelectedCulture = new System.Globalization.CultureInfo("es-CL");
System.Threading.Thread.CurrentThread.CurrentCulture = userSelectedCulture;
in MainActivity OnCreate method but it did not work.
Regards
Jaime
I have this code. which creates a event in my google calendar.
client = Signet::OAuth2::Client.new(client_options)
client.update!(session[:authorization])
service = Google::Apis::CalendarV3::CalendarService.new
service.authorization = client
event = Google::Apis::CalendarV3::Event.new({
start: Google::Apis::CalendarV3::EventDateTime.new(
date_time: cf_event.starts_at.to_datetime.rfc3339,
time_zone: 'America/Monterrey'
),
end: Google::Apis::CalendarV3::EventDateTime.new(
date_time: cf_event.ends_at.to_datetime.rfc3339,
time_zone: 'America/Monterrey'
),
summary: cf_event.title
})
It is a basic example my cf_event object has the starts_at attr, which is a timeWithZone.
so i had to do cf_event.starts_at.to_datetime.rfc3339.
Output
"2019-03-15T17:50:00+00:00"
The problem is, that the code creates, the event but with -6 hours.
If i go to google calendars my event it´s the day 15 at (11 - 11:50), and not (17 - 17:50)
what am i doing wrong?
You are inputting the time as 17:50:00 in UTC+0 (the +00:00 from your date_time stands for UTC or UTC+0), however, you specified a time_zone where you used Monterrey which follows the time zone UTC-6.
My guess here is that, your code takes 17:50:00 in UTC+0 then converts it to Monterrey time zone UTC-6 which results to 11:50:00. Either try removing the +00:00 or try making it -06:00.
I have been assigned a task to display server clock to the user. I can do that using jquery, but we need to display our server clock which will be like a clock.
Like i have date format like : 2016-06-30 10:27:32 and it should be updated like a timer or a clock is running. I have search a lot on internet, but i did not get any clue.
Please suggest me the solution.
Probably the best solution is to get time/date from server and increment it via jquery/JS.
<?php $currentTime = getdate(); ?>
<script>
var date = new Date(Date.UTC(<?php echo $currentTime['year'] .",".
$currentTime['mon'] .",".
$currentTime['mday'] .",".
$currentTime['hours'] .",".
$currentTime['minutes'] .",".
$currentTime['seconds']; ?>));
setInterval(function() {
date.setSeconds(date.getSeconds() + 1);
console.log((date.getHours() +':' + date.getMinutes() + ':' + date.getSeconds() ));
}, 1000);
</script>
Because setInterval isn't the most precise function, you should probably update your date once per minute via AJAX request.
My Sinatra app is creating a simple object and persisting it to Postgres:
post '/' do
event = Event.new(params)
event.created_at = Time.now.utc
event.date = next_date(params[:dayofweek], params[:time]) if params[:dayofweek] && params[:time]
if event.save
status 201
event.to_json
else
json_status 400, event.errors.to_hash
end
def next_date(dayofweek, hour)
...
# some calculations that effectively culminate in the final line below
...
my_time = Time.utc(2012, 11, 9, 12, 0, 0) ## => 2012-11-09 12:00:00 UTC
end
Object saves successfully. But when I retrieve the object from my development environment I get (json):
{ ..., "date":"2012-11-23T20:00:00-08:00" } #notice the PST offset of -08:00.
I'm expecting the UTC time zone or +00:00. For some reason my development workstation, which is in PST, is factoring in its own time zone when saving to Postgres...at least that what it appears to be doing?!?
Sending the same code to the production server (Heroku) stores same data with proper offset of +00:00
How can I make my development workstation act like the production one? Or, how should I be creating a proper UTC Date object in Sinatra?
First verify that your data does a round-trip successfully:
event.created_at = Time.now.utc
event.date = ...whatever...
tmp_created_at = event.created_at
tmp_date = event.date
event.save
event.reload!
tmp_created_at == event.created_at or raise "created_at failed"
tmp_date == event.date_at or raise "date failed"
Second, verify that the JSON is accurate.
compare the JSON time string to the expected time
the JSON time string has the -08:00
is the JSON string the same actual time?
For example, if you expect 10:00Z, does the JSON show 02:00-08:00 (i.e. the same actual time) or 10:00-08:00 (not the same actual time-- this is eight hours later).
If the data round-trip works, and the JSON is the same actual time, then look at whatever JSON library you're using to print the strings. Look for a method like "iso8601" that will print the time in standard UTC format.
Also, it may be helpful to know that Postgres saves timestamps without the time zone by default.
"The SQL standard requires that writing just timestamp be equivalent to timestamp without time zone, and PostgreSQL honors that behavior. (Releases prior to 7.3 treated it as timestamp with time zone.) timestamptz is accepted as an abbreviation for timestamp with time zone; this is a PostgreSQL extension."
You can see this by describing the table, which may look something like this:
# \d events
Table "public.events"
Column | Type | Modifiers
-----------+-----------------------------+-----------------------------------
id | integer | not null default
name | character varying(255) |
created_at | timestamp without time zone | not null
updated_at | timestamp without time zone | not null
date | timestamp with time zone | not null
More info based on OP's feedback...
OP says: I'm using DataMapper and after digging around on their site I found "time properties will always be stored and retrieved in the timezone the datastore is set to" and a link to a gem that'll force a specific zone.
Because the round-trip shows a problem, try using a current version of the connection library e.g. a current DataMapper, and also try a current version of any similar library e.g. ActiveRecord (version 3.2.8 at the time of this writing).