Reputation: 191
I am trying to get the difference between the machine local time to the east coast of the US, though that is non specific.
I am using the following but it always returns the difference from UTC and not the timezone set by the PC.
LocalDateTime now = LocalDateTime.now();
ZoneId zone = ZoneId.of("America/New_York");
ZoneOffset zoneOffSet = zone.getRules().getOffset(now);
System.out.println(zoneOffSet + " " + ZonedDateTime.now() + " " + Instant.now());
No matter which time zone I set my PC time to it always shows -04:00 for zoneOffSet.
What am I doing wrong here?
Upvotes: 0
Views: 284
Reputation: 86379
The reason I need this is I am making an app that requires saved appointments based on New York time zone. No matter where you are in the world your local timezone will lock to the appointment time of 8A.M. to 5P.M. in NewYork. This allows the clients to see what time it will be in their area when matching the NY TZ.
In Java it’s easier to convert a time between the user’s time zone and America/New_York time zone than it is to calculate the difference. Why try something complicated when what you need is simple?
I am assuming the following constants:
static final ZoneId SERVER_ZONE = ZoneId.of("America/New_York");
static final LocalTime OPENS_SERVER_TIME = LocalTime.of(8, 0);
static final LocalTime CLOSES_SERVER_TIME = LocalTime.of(17, 0); // 5 PM
To convert a time from New York time to the user’s time zone we need a date. The UTC offset for New York changes between standard and summer time (DST), and the same could be true for the user’s time zone (and if it is, the changeover dates need not coincide).
LocalDate date = LocalDate.of(2021, Month.OCTOBER, 20);
ZoneId userZone = ZoneId.systemDefault();
ZonedDateTime openInUserZone = date.atTime(OPENS_SERVER_TIME)
.atZone(SERVER_ZONE)
.withZoneSameInstant(userZone);
System.out.println(openInUserZone);
I ran this in Asia/Dushanbe time zone and got this output:
2021-10-20T17:00+05:00[Asia/Dushanbe]
17:00 at UTC offset +05:00 agrees with 8 AM at offset -04:00, the offset used in New York in October. For the opposite conversion just switch the two time zones in the code that converts.
Upvotes: 0
Reputation: 79580
Although you can get the timezone offset using ZoneId#getRules#getOffset(LocalDateTime)
, for simplicity, I prefer using the current ZoneId#getRules#getOffset(Instant)
to get this value.
Demo:
import java.time.Duration;
import java.time.Instant;
import java.time.ZoneId;
public class Main {
public static void main(String args[]) {
// Tests
ZoneId systemZoneId = ZoneId.systemDefault();
ZoneId zoneIdNy = ZoneId.of("America/New_York");
ZoneId zoneIdIndia = ZoneId.of("Asia/Kolkata");
System.out.printf("Difference between %s and %s: %s%n", systemZoneId.getId(), zoneIdNy.getId(),
timezoneOffsetDiffBewteen(systemZoneId, zoneIdNy));
System.out.printf("Difference between %s and %s: %s%n", systemZoneId.getId(), zoneIdIndia.getId(),
timezoneOffsetDiffBewteen(systemZoneId, zoneIdIndia));
}
static String timezoneOffsetDiffBewteen(ZoneId source, ZoneId target) {
Instant instant = Instant.now();
long offsetSecondsSource = source.getRules().getOffset(instant).getTotalSeconds();
long offsetSecondsTarget = target.getRules().getOffset(instant).getTotalSeconds();
long diff = offsetSecondsTarget - offsetSecondsSource;
Duration duration = Duration.ofSeconds(diff);
return String.format("%s%02d:%02d", diff < 0 ? "-" : "+", Math.abs(duration.toHoursPart()),
duration.toMinutesPart());
}
}
Output:
Difference between Europe/London and America/New_York: -05:00
Difference between Europe/London and Asia/Kolkata: +04:30
Learn more about the modern Date-Time API* from Trail: Date Time.
* If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring. Note that Android 8.0 Oreo already provides support for java.time
.
Upvotes: 0
Reputation: 191
I took what I had posted and added a bit to it to get my local time zone and subtract from one another to get the difference in time zone from JVM(My PC TimeZone) from New Yorks to get the timezone difference.
I then took your code and did the same for the same output but it matches yours so easier for others to read.
ZoneId z = ZoneId.of( "America/New_York" ) ;
ZoneRules rules = z.getRules() ;
ZoneOffset offset = rules.getOffset( now ) ;
int offsetInSeconds_NewYork = offset.getTotalSeconds() ;
int offsetInSeconds_MyDefaultZone =
ZoneId.systemDefault().getRules().getOffset( now ).getTotalSeconds() ;
System.out.println(offsetInSeconds_MyDefaultZone / 60 /60);
System.out.println((offsetInSeconds_NewYork / 60 /60) - (offsetInSeconds_MyDefaultZone / 60 /60));
The reason I need this is I am making an app that requires saved appointments based on New York time zone. No matter where you are in the world your local timezone will lock to the appointment time of 8A.M. to 5P.M. in NewYork. This allows the clients to see what time it will be in their area when matching the NY TZ.
Again thanks for this as I was in the mindset that the code I posted in the OP would decern the difference(.offset) of my PC(JVM) TZ to that of New York. Grabbing both and subtracting seemed to be the only real way. Shame that is not a feature in Java. But you can see my confusion in rules.getOffset( now ) as now can change to any location but it never adjusts the offset to anything but UTC. Very strange.
Thanks for push to settle my head.
Upvotes: 0
Reputation: 340118
LocalDateTime
is not a momentGeneral tip: Never call LocalDateTime.now()
. I cannot imagine a scenario where that is the right thing to do.
The LocalDateTime
class purposely lacks any concept of time zone or offset-from-UTC. So LocalDateTime
cannot represent a moment, cannot track a specific point on the timeline.
I cannot discern from your prose exactly what is your goal. But looking at your code, it seems you want to know what is the current offset-from-UTC in effect for a particular time zone. That is quite easy.
A ZoneId
represents a particular time zone. Each time zone has a ZoneRules
object containing the history of the past, present, and future changes to the offset used by the people in that region.
Pass a moment (an Instant
) to those rules to ask for the offset in effect at that time. The result is a ZoneOffset
, a number of hours-minutes-seconds.
ZoneId z = ZoneId.of( "America/New_York" ) ;
ZoneRules rules = z.getRules() ;
Instant now = Instant.now() ; // Capture the current moment as seen in UTC (an offset of zero hours-minutes-seconds).
ZoneOffset offset = rules.getOffset( now ) ;
You can generate text in standard ISO 8601 format to represent that offset value by calling ZoneOffset#toString
.
ZonedDateTime zdt = now.atZone( z ) ;
String message = zdt.toString() + " has an offset of " + offset + "." ;
System.out.println( message ) ;
See this code run live at IdeOne.com.
2021-10-09T00:36:54.432057-04:00[America/New_York] has an offset of -04:00.
You said:
No matter what I set my PC time to it always shows -04:00 for zoneOffSet.
Of course. No matter where you are in the world, the people in the New York region set their clocks four hours behind UTC. The default time zone used on your computer has no impact on that fact.
If you want to compare the offset of your particular time zone against the offset of another time zone, run the same code as seen above to get a second ZoneOffset
for the same Instant
. To access your JVM’s current default time zone, call ZoneId.systemDefault
.
You could compare them by converting each offset to a total number of seconds (positive or negative). Call ZoneOffset#getTotalSeconds
.
int offsetInSeconds_NewYork = offset.getTotalSeconds() ;
int offsetInSeconds_MyDefaultZone = ZoneId.systemDefault().getRules().getOffset( now ).getTotalSeconds() ;
Upvotes: 1