What is the Zone Id for GMT in Java 8 - java-8

I want to get the difference in seconds to find whether the system timezone is ahead or behind the remote timezone. Here the remote timezone value is "GMT" which i fetch from Database. It could be "US/Eastern", which i convert to "America/New_York". But for GMT, im getting ERROR.
ZoneId.systemDefault().getRules().getOffset(Instant.now()).getTotalSeconds()
- ZoneId.of("GMT").getRules().getOffset(Instant.now()).getTotalSeconds()
But it gives the following error,
Exception in thread "main" java.time.DateTimeException: Invalid ID for ZoneOffset, invalid format:
at java.time.ZoneOffset.of(Unknown Source)
at java.time.ZoneId.of(Unknown Source)
at java.time.ZoneId.of(Unknown Source)
How to resolve this error ?
What to use in place of GMT ??

Use Etc/UTC
import java.time.Instant;
import java.time.ZoneId;
public class Main {
public static void main(String args[]) {
System.out.println(ZoneId.of("Etc/UTC").getRules().getOffset(Instant.now()).getTotalSeconds());
}
}
Output:
0

The official answer is:
Etc/GMT
It’s the same as the Etc/UTC suggested in the other answers except for the name.
For the sake of completeness there are a number of aliases for the same, many of them deprecated, not all. You can find them in the link.
And I am not disagreeing with the comments telling you to prefer UTC. I just wanted to answer the question as asked.
For your case you should not need to ask at all though. ZoneId.of("GMT").getRules().getOffset(Instant.now()).getTotalSeconds() should always yield 0, so there is no need to subtract anything. I would either insert a comment why I don’t or subtract a well-named constant with the value 0.
Link: List of tz database time zones

It's ZoneId.of("UTC")...
Here's evidence:
public static void main(String[] args) {
// define the ZoneId
ZoneId utc = ZoneId.of("UTC");
// get the current date and time using that zone
ZonedDateTime utcNow = ZonedDateTime.now(utc);
// define a formatter that uses O for GMT in the output
DateTimeFormatter gmtStyleFormatter = DateTimeFormatter
.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSS O");
// and print the datetime using the default DateTimeFormatter and the one defined above
System.out.println(utcNow + " == " + utcNow.format(gmtStyleFormatter));
}
output (some moments ago):
2020-09-16T08:02:34.717Z[UTC] == 2020-09-16T08:02:34.717 GMT
Getting the total zone offset in seconds of this zone by
utc.getRules().getOffset(Instant.now()).getTotalSeconds();
will result in 0, because this zone has no offset.

Related

Spring Scheduled annotation with zone EST, not working

I am trying to create a scheduler to run in EST timezone. For that, I have added #Scheduled annotation upon the scheduled method. The method is given below. I want this method to run daily at 05:00 am EST on Mon-Friday, but it runs at 3:30 am IST (6:00 pm EST).
#Scheduled(cron = "0 0 5 * * MON-FRI", zone = "EST")
public void jobRunDaily() {
logger.info("jobRunDaily : called");
this.sendEmailDaily();
}
As described in the documentation, zone accepts IDs that are valid for TimeZone.getTimeZone(String).
In TimeZone documentation you will find the following for such method:
the ID for a TimeZone, either an abbreviation such as "PST", a full name such as "America/Los_Angeles", or a custom ID such as "GMT-8:00". Note that the support of abbreviations is for JDK 1.1.x compatibility only and full names should be used.
Meaning that full names should be used instead of your "EST" abbreviation.

changed laravel app timezone, time got from db did not change

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.

Instant differs from the Timestamp in Java?

I seem to be getting different representations of Java's time stamp as follows:
en_US
2017-06-10 14:34:35.088
2017-06-10T18:34:35.102Z
with following invocations:
System.out.println(Locale.getDefault());
System.out.println(new Timestamp(System.currentTimeMillis()));
System.out.println(Instant.now());
What additional configurations will help to equalize the the 4 hr offset between time representations shown above? Thanks.
One is your local time and one is UTC. This depends more on the way it is printed than on the actual (internal) value.
To have both shown equal, you can
Set your local time zone to UTC by passing -Duser.timezone=UTC to your VM.
Format the Instant to your local time zone:
DateTimeFormatter formatter =
DateTimeFormatter.ISO_LOCAL_DATE_TIME.withZone(ZoneId.systemDefault());
System.out.println(formatter.format(Instant.now()));
Convert the Timestamp to an Instant:
new Timestamp(System.currentTimeMillis()).toInstant();
Full code:
public static void main(String[] args) {
DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME.withZone(ZoneId.systemDefault());
Timestamp timestamp = new Timestamp(System.currentTimeMillis());
Instant instant = Instant.now();
System.out.println("Timestamp: " + timestamp);
System.out.println("Instant: " + instant);
System.out.println("Instant to local: " + formatter.format(instant));
System.out.println("Timestamp to UTC: " + timestamp.toInstant());
}
Will print out (in my local time zone):
Timestamp: 2017-06-10 21:17:13.935
Instant: 2017-06-10T19:17:13.935Z
Instant to local: 2017-06-10T21:17:13.935
Timestamp to UTC: 2017-06-10T19:17:13.935Z
So there is "some global setting", although it might not do what you want. An Instant will always be printed in UTC by default.
If you want to work with local dates only and you are not restricted to Instant, there are two* more options:
Convert the Instant to ZonedDateTime:
ZonedDateTime.ofInstant(Instant.now(), ZoneId.systemDefault());
Or skip the Instant altogether in favor of ZonedDateTime.now()
*Depending on your needs you can exchange ZonedDateTime with OffsetDateTime or LocalDateTime.
Edit: The magical way.
public static void main(String[] args) throws Exception {
Field field = DateTimeFormatter.class.getField("ISO_INSTANT");
field.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.set(null, DateTimeFormatter.ISO_LOCAL_DATE_TIME.withZone(ZoneId.systemDefault()));
System.out.println(new Timestamp(System.currentTimeMillis()));
System.out.println(Instant.now());
}
Use reflection to change DateTimeFormatter.ISO_INSTANT to a formatter that uses your local time. Might not work with a SecurityManager and might have one or another unwanted side effect. See e.g. Change private static final field using Java reflection for details.

How to set Local Timezone when saving time into DB in Magneto

I have applied following things to make Default time zone to my local timezone i.e. 'Asia/Calcutta' --
1) changed in config.xml -
<general>
<locale>
<code>en_US</code>
<timezone>Asia/Calcutta</timezone>
</locale>
</general>
2) Changed in Mage.php -
if (is_readable($localConfigFile)) {
$localConfig = simplexml_load_file($localConfigFile);
date_default_timezone_set('Asia/Calcutta');
if (($date = $localConfig->global->install->date) && strtotime($date)) {
self::$_isInstalled = true;
}
}
Now when I am trying to insert any time in db using this code
Mage::getModel('core/date')->date('Y-m-d H:i:s');,
it does not work according to current timezone and saves 5:30 hours ahead date in DB. can anyone tell me how can I do it or Have I done something wrong in default timezone settings.

Sinatra/Ruby time zone troubles between development & production

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).

Resources