In a android form , i am accepting a GMT value(offset) from user such a +5:30 , +3:00.
and from this value , i want to calculate the timeZone that is "India/Delhi".
Any ideas on how to do it ......Plzz
If you already have a specific instant in time at which that offset is valid, you could do something like this:
import java.util.*;
public class Test {
public static void main(String [] args) throws Exception {
// Five and a half hours
int offsetMilliseconds = (5 * 60 + 30) * 60 * 1000;
for (String id : findTimeZones(System.currentTimeMillis(),
offsetMilliseconds)) {
System.out.println(id);
}
}
public static List<String> findTimeZones(long instant,
int offsetMilliseconds) {
List<String> ret = new ArrayList<String>();
for (String id : TimeZone.getAvailableIDs()) {
TimeZone zone = TimeZone.getTimeZone(id);
if (zone.getOffset(instant) == offsetMilliseconds) {
ret.add(id);
}
}
return ret;
}
}
On my box that prints:
Asia/Calcutta
Asia/Colombo
Asia/Kolkata
IST
(As far as I'm aware, India/Delhi isn't a valid zoneinfo ID.)
If you don't know an instant at which the offset is valid, this becomes rather harder to really do properly. Here's one version:
public static List<String> findTimeZones(int offsetMilliseconds) {
List<String> ret = new ArrayList<String>();
for (String id : TimeZone.getAvailableIDs()) {
TimeZone zone = TimeZone.getTimeZone(id);
if (zone.getRawOffset() == offsetMilliseconds ||
zone.getRawOffset() + zone.getDSTSavings() == offsetMilliseconds) {
ret.add(id);
}
}
return ret;
}
... but that assumes that there are only ever two offsets per time zone, when in fact time zones can change considerably over history. It also gives you a much wider range of IDs, of course. For example, an offset of one hour would include both Europe/London and Europe/Paris, because in summer time London is at UTC+1, whereas in winter Paris is at UTC+1.
Many timezone IDs can have the same timezone offset
Normally, the relation between timezone ID and timezone offset is many to one i.e. many timezone IDs can have the same timezone offset. In fact, on account of DST, a timezone ID can have two timezone offsets e.g. the timezone offsets for the timezone ID, "Europe/London" are "+00:00" and "+01:00" in the summer and in the winter respectively.
Apart from this, there have been instances when the timezone offset of states has been changed by their rulers/politicians many times as also mentioned by Ole V.V. in the following comment:
The relation between timezone ID and timezone offset is many to one …
True if you are considering one point in time. If looking at history,
it’s really many to many.
So, taking DST and these historical events into account, we can say that the relation between timezone ID and timezone offset is many to many.
Solution using java.time, the modern Date-Time API:
You can traverse ZoneId.getAvailableZoneIds() to filter and collect the ZoneId whose ZoneOffset is equal to the ZoneOffset created using the input offset string.
Demo:
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) {
// Test
System.out.println(getTimeZoneId("+5:30"));
System.out.println(getTimeZoneId("-5:00"));
}
static List<String> getTimeZoneId(String input) {
List<String> list = new ArrayList<>();
// Convert +5:30 to +05:30; similarly, -5:00 to -05:00
String[] arr = input.split(":");
if (arr.length == 2) {
input = arr[0].substring(0, 1) + String.format("%02d", Integer.parseInt(arr[0].replaceAll("\\D", ""))) + ":"
+ arr[1];
ZoneOffset offset = ZoneOffset.of(input);
Instant now = Instant.now();
list = ZoneId.getAvailableZoneIds()
.stream()
.filter(tzId -> ZoneId.of(tzId).getRules().getOffset(now).equals(offset))
.collect(Collectors.toList());
}
return list;
}
}
Output:
[Asia/Kolkata, Asia/Colombo, Asia/Calcutta]
[America/Panama, America/Chicago, America/Eirunepe, Etc/GMT+5, Mexico/General, America/Porto_Acre, America/Guayaquil, America/Rankin_Inlet, US/Central, America/Rainy_River, America/Indiana/Knox, America/North_Dakota/Beulah, America/Monterrey, America/Jamaica, America/Atikokan, America/Coral_Harbour, America/North_Dakota/Center, America/Cayman, America/Indiana/Tell_City, America/Mexico_City, America/Matamoros, CST6CDT, America/Knox_IN, America/Bogota, America/Menominee, America/Resolute, SystemV/EST5, Canada/Central, Brazil/Acre, America/Cancun, America/Lima, America/Bahia_Banderas, US/Indiana-Starke, America/Rio_Branco, SystemV/CST6CDT, Jamaica, America/Merida, America/North_Dakota/New_Salem, America/Winnipeg]
ONLINE DEMO
Note: The regex pattern, \D specifies a non-digit character.
Learn more about the modern Date-Time API from Trail: Date Time.
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. 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 and How to use ThreeTenABP in Android Project.
If I have correctly interpreted your question then try this,
final SimpleDateFormat date=
new SimpleDateFormat("EEE, MMM d, yyyy hh:mm:ss a z");
date.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println("GMT time: " + date.format(currentTime));
In this you can add your offset. see if this helps you.
Related
I want an epoch of every day at 12pm. I have tried to make a function that makes a string of date time and has to convert into an epoch but this doesn't work and also it shows 12pm to 0(zero) I don't know why
here's what I have tried but show error:
Calendar now = Calendar.getInstance();
int year = now.get(Calendar.YEAR);
int month=now.get(Calendar.MONTH)+1;
int date=now.get(Calendar.DATE);
String yearInString = String.valueOf(year);
String monthInString=String.valueOf(month);
if(monthInString.length()==1){
monthInString="0"+monthInString;
}
String dateInString=String.valueOf(date);
if(dateInString.length()==1){
dateInString="0"+dateInString;
}
int hour=now.get(Calendar.HOUR);
String hourInString=String.valueOf(hour);
int minute=now.get(Calendar.MINUTE);
String minuteInString=String.valueOf(minute);
if(minuteInString.length()==1){
minuteInString="0"+minuteInString;
}
int second=now.get(Calendar.SECOND);
String secondInString=String.valueOf(second);
String HRD=yearInString+"-"+monthInString+"-"+dateInString+" "+hourInString+":"+minuteInString+":"+secondInString;
System.out.println(HRD);
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-dd-MM HH:mm:ss.SSS");
LocalDateTime dt = LocalDateTime.parse(HRD, dtf);
Instant instant = dt.toInstant(ZoneOffset.UTC);
System.out.println(instant.toEpochMilli());
and also tried this
Date date1 = dateFormat.parse(HRD);
long epoch = date1.getTime();
System.out.println(epoch);
but show error
Exception in thread "main" java.time.format.DateTimeParseException: Text '2021-10-06 0:29:43' could not be parsed at index 11
at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2052)
at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1954)
at java.base/java.time.LocalDateTime.parse(LocalDateTime.java:494)
at customepoch.main(customepoch.java:35)
java.time
The java.util Date-Time API is outdated and error-prone. It is recommended to stop using it completely and switch to the modern Date-Time API*.
Solution using java.time, the modern Date-Time API: From the OffsetDateTime at 12 pm, you can get the corresponding Instant using OffsetDateTime#toInstant and from this Instant, you can get the epoch milliseconds.
Demo:
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.temporal.TemporalAdjusters;
public class Main {
public static void main(String[] args) {
OffsetDateTime todayAtNoon = OffsetDateTime.of(LocalDate.now(ZoneOffset.UTC), LocalTime.NOON, ZoneOffset.UTC);
OffsetDateTime lastDateOfMonth = todayAtNoon.with(TemporalAdjusters.lastDayOfMonth());
for (OffsetDateTime odt = todayAtNoon; !odt.isAfter(lastDateOfMonth); odt = odt.plusDays(1)) {
System.out.println(odt.toInstant().toEpochMilli());
}
}
}
Output:
1633521600000
1633608000000
1633694400000
...
ONLINE DEMO
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.
What went wrong in your code?
There are already two answers showing you how to obtain the numbers you want. I am not repeating that.
Rather I am posting this answer because I sensed a curiosity: Why did your code show 12 PM as 0 (zero)? Why did you get the error (exception)? This is what I am addressing here.
First as has been said directly or indirectly you were using the Calendar class for obtaining the current time in your time zone. Calendar is poorly designed and long outdated. Don’t do that.
Your conversion from Calendar to Instant was very, very complicated. If you had got a Calendar from some legacy API and wanted to convert it (which you don’t want for your current purpose), all you had needed was:
Instant instant = now.toInstant();
That’s right, since Java 8 Calendar has got a toInstant method for the conversion. The other old date and time classes have got similar conversion methods added.
You tried:
int hour=now.get(Calendar.HOUR);
Calendar.HOUR is for hour within AM or PM from 0 though 11. This explains why you got 0 for 12 PM. Calendar.HOUR_OF_DAY is for hour of day from 0 through 23. It’s just one of the many confusing points about Calendar and one of the many reasons why I recommend you don’t use it.
You prepended month, day of month and minute with 0 to make sure you had got two digits. You didn’t do the same for hour and second. Since your hour was 0, it was only one digit and did not match HH in the format pattern, which requires two digits. This caused the exception that you reported.
You tried this formatter for parsing:
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-dd-MM HH:mm:ss.SSS");
The string you built did not include milliseconds. You should either leave out .SSS or you should add the fraction of second to your string.
This seems to conflict with your intention:
Instant instant = dt.toInstant(ZoneOffset.UTC);
Since you wanted the time in your local time zone, it should have been:
Instant instant = dt.toInstant(ZoneId.systemDefault());
Say you have your local timezone properly set for your JVM so that it is available with ZoneId.systemDefault(). Assume also you start from today (06-Oct-2021). Then your code would be:
public static void main(String[] args) {
LocalDateTime start = LocalDateTime.of(2021, Month.OCTOBER, 6, 12, 0);
for (long i = 0; i < 10; i++) {
System.out.println(
start
.plusDays(i)
.atZone(ZoneId.systemDefault())
.toEpochSecond()
);
}
}
I have a method which generates a random date and time.
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.Period;
public String getRandomFormattedDateAndTime() {
LocalDateTime date = generateRandomDateAndTimeInPast();
return formatDate(date);
}
public LocalDateTime generateRandomDateAndTimeInPast() {
return LocalDateTime.now()
.minus(Period.ofDays(
(new Random().nextInt(365 * 2))
));
}
public static String formatDate(LocalDateTime date) {
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(DATE_TIME_FORMAT_PATTERN);
return dateTimeFormatter.format(date);
}
and the printed output is something like "2020-08-07T08:57:09Z"
However, i need to obtain the same value with time zone format 2020-08-07T10:57:09+02:00 which has the +02:00 (my local time).
I have seen several questions and pages like this, but they do not give me a clue.
I hope this is what you are looking for:
ZonedDateTime zonedDateTime = ZonedDateTime.now().minus(Period.ofDays((new Random().nextInt(365 * 2))));
System.out.println("Date Time:" + zonedDateTime.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
Output: Date Time:2019-07-13T14:27:51.909+05:30
Note: 05:30 is my time zone (local) offset
In your example you're using the type LocalDateTime. LocalDateTime can't be formatted with timezone pattern as it doesn't contains any timezone information...
Switch to ZonedDateTime will solve your problem.
Not sure why people are involving ZonedDateTime here, but it seems to be a valid approach...
However, I want to add another one, that is the use of an OffsetDateTime.
This is an adjusted version of your method generateRandomDateAndTimeInPast:
public static OffsetDateTime generateRandomDateAndTimeInPast(int offset) {
return OffsetDateTime.now(ZoneOffset.ofHours(offset))
.minusDays(
ThreadLocalRandom.current()
.nextInt(365 * 2)
);
}
An example use could look like this, please note the implicit call to OffsetDateTime.toString() by directly System.outing the instance of OffsetDateTime. You can alter the output by calling OffsetDateTime.format(DateTimeFormatter).
public static void main(String[] args) {
OffsetDateTime odt = generateRandomDateAndTimeInPast(2);
System.out.println(odt);
}
This prints out datetimes formatted like the following (randomly generated) one:
2020-10-14T10:44:23.304+02:00
If you need a LocalDateTime (that won't contain or print any offset), you can simply get it from the OffsetDateTime like this:
LocalDateTime ldt = odt.toLocalDateTime();
A ZonedDateTime has that method, too, so if you use that or an OffsetDateTime you can always have the LocalDateTime they are based on by calling toLocalDateTime().
You have not provided the code of your method, formatDate(LocalDate). However, you have mentioned that String getRandomFormattedDateAndTime() is returning you 2020-08-07T08:57:09Z. The following method, getDateTimeInMyTz(String) provides you with what you are looking for:
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZoneOffset;
public class Main {
public static void main(String[] args) {
// Test
System.out.println(getDateTimeInMyTz("2020-08-07T08:57:09Z"));
}
public static String getDateTimeInMyTz(String strDtUtc) {
Instant instant = Instant.parse(strDtUtc);
ZoneOffset offset = ZoneId.systemDefault().getRules().getOffset(instant);
return instant.atOffset(offset).toString();
}
}
Output in my timezone which has an offset of +01:00 hours:
2020-08-07T09:57:09+01:00
Usage: Replace getDateTimeInMyTz("2020-08-07T08:57:09Z") with getDateTimeInMyTz(getRandomFormattedDateAndTime()).
If you share the code of your method, formatDate(LocalDate), I can suggest further simplification.
Learn more about java.time, the modern Date-Time API* from Trail: Date Time.
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. 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 and How to use ThreeTenABP in Android Project.
In my Firebase database, for each item present, I save the date of when it is created and inserted into the db.
The date is saved using the ServerValue.TIMESTAMP, the value is saved as a Map. How can I compare the saved value to today's current date in Java?
I need to know if the date of the item is older than 14 days. THX
The number in your screenshot represents the number of milliseconds from the epoch which you can convert into an Instant using Instant.ofEpochMilli. Once you have Instant, you can convert it into other date-time types e.g.
import java.time.Instant;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
public class Main {
public static void main(String[] args) {
ZonedDateTime zdt = ZonedDateTime.ofInstant(Instant.ofEpochMilli(1616686018322L), ZoneOffset.UTC);
System.out.println(zdt);
ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC);
if (now.minusDays(14).isAfter(zdt)) {
System.out.println("The item is 14 or more days older");
} else {
System.out.println("The item less than 14 days older");
}
}
}
Output:
2021-03-25T15:26:58.322Z
The item less than 14 days older
Note that the comparison shown above takes all units (up to nanoseconds precision) into account. However, if you want to compare only dates (not date & time), you can perform the comparison on ZonedDateTime#toLocalDate.
Learn more about the modern date-time API from Trail: Date Time.
I want to subtract 7 days from Now, but keeping the time, so If now is
12/09/2018 at 18:30, get 05/09/2018 at 18:30...
I've tried:
public static Date subtractDays (int numDaysToSubstract) {
LocalDate now = LocalDate.now().minusDays(numDaysToSubstract);
return Date.from(now.atStartOfDay(ZoneId.systemDefault()).toInstant());
}
But I got 05/09/2018 at 00:00
As others have suggested, LocalDate and atStartOfDay should have been red flags based on just their name. They are the wrong type to describe a time and the wrong method to maintain the time.
It's also kind of pointless to go through LocalDateTime to then convert it to an Instant. Just use an Instant straight up
public static Date subtractDays(int numDaysToSubstract) {
return Date.from(Instant.now().minus(numDaysToSubstract, ChronoUnit.DAYS));
// or
// return Date.from(Instant.now().minus(Duration.ofDays(numDaysToSubstract)));
}
(I assume you're using java.util.Date because of compatibility with some old API.)
It’s unclear from the code in the other answers posted until now how they handle summer time (DST) and other time anomalies. And they do that differently. To make it clearer that you want 18.30 last week if time now is 18.30, no matter if a transition to or from summer time has happened in the meantime I suggest using ZonedDateTime:
System.out.println("Now: " + Instant.now());
Instant aWeekAgo = ZonedDateTime.now(ZoneId.of("Europe/Madrid"))
.minusWeeks(1)
.toInstant();
System.out.println("A week ago in Spain: " + aWeekAgo);
Since summer time in Spain hasn’t ended or begun within the last week, running the code snippet just now gave the same time of day also in UTC (which is what Instant prints):
Now: 2018-09-13T09:46:58.066957Z
A week ago in Spain: 2018-09-06T09:46:58.102680Z
I trust you to adapt the idea to your code.
Use class LocalDateTime instead of LocalDate (which doesn't contain a time component..)
You should use LocalDateTime instead of LocalDate
LocalDate is just a description of the date without time or time-zone
public static Date subtractDays (int numDaysToSubstract) {
LocalDateTime now = LocalDateTime.now().minusDays(numDaysToSubstract);
return Date.from(now.atZone(ZoneId.systemDefault()).toInstant());
}
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class Test {
public static String subtractDays (int numDaysToSubstract) {
LocalDateTime now = LocalDateTime.now().minusDays(numDaysToSubstract);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formatDateTime = now.format(formatter);
return formatDateTime;
}
public static void main(String[] args){
System.out.println(subtractDays(7));
}
}
I want to get the difference of current time (Which is IST) and the time which is stored in DB(EST). In order to that I am trying to convert current time to EST before calculating the difference. But its not working. In the following approach,
local time is not getting converted to EST only. Could you please suggest me the better way to do it ?
The return type of getModifiedDate is java.sql.Timestamp and the data type
of the column is DATE
Code :
Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("EST"));
cal.setTimeInMillis(System.currentTimeMillis());
cal.getTimeInMillis() - emp.getModifiedDate().getTime();
I was trying to do it using SimpleDateFormat , But I am not sure how to proceed with that approach.
If you can provide the code snippet that will be helpful
You can try java.util.TimeZone
long now = System.currentTimeMillis();
long diff = TimeZone.getTimeZone("IST").getOffset(now) - TimeZone.getTimeZone("EST").getOffset(now);
getOffset - Returns the offset of this time zone from UTC at the specified date
If you have access to Java 8, then it may be just as easy to calculate the difference between the two dates directly, rather than adjusting to a target time zone first.
You could do this using ZonedDateTime from the java.time package:
// Our timestamp
Timestamp ts = emp.getModifiedDate();
// Convert timestamp to ZonedDateTime in the correct time zone
ZonedDateTime estTime = ts.toLocalDateTime().atZone(ZoneId.of("America/New_York"));
// Could pass in ZoneId.of("Asia/Kolkata") argument to now(...), but not required
// as "now" is the same instant in all time zones.
ZonedDateTime zonedNow = ZonedDateTime.now();
// Can use other ChronoUnit values if required.
long timeDiff = ChronoUnit.MILLIS.between(zonedNow, estTime);
// Use timeDiff as required
I suggest using the java.time API of JDK 8 which simplifies this to a great extent. Consider the following example:
Timestamp t = emp.getModifiedDate();
Duration.between(t.toInstant(), ZonedDateTime.now(ZoneId.of("Asia/Kolkata")).toInstant());
The timestamp retrieved from DB has been converted to Instant which is in UTC, similarly the current time in Asia/Kolkata zone has been converted to Instant and the Duration between the two has been calculated.You can retrieve the required information from the duration.
You can find it using java.time.Duration which is modelled on ISO-8601 standards and was introduced with Java-8 as part of JSR-310 implementation. With Java-9 some more convenience methods were introduced.
import java.time.Duration;
import java.time.LocalDate;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
public class Main {
public static void main(String[] args) {
// Test
System.out.println(formatDuration(diffBetweenTimeZones("Asia/Kolkata", "America/New_York")));
System.out.println(formatDuration(diffBetweenTimeZones("America/New_York", "Asia/Kolkata")));
// You can use the returned value to get the ZoneOffset which you can use for
// other processing e.g.
ZoneOffset offset = ZoneOffset.of(formatDuration(diffBetweenTimeZones("Asia/Kolkata", "America/New_York")));
System.out.println(offset);
System.out.println(OffsetDateTime.now(offset));
}
static Duration diffBetweenTimeZones(String tz1, String tz2) {
LocalDate today = LocalDate.now();
return Duration.between(today.atStartOfDay(ZoneId.of(tz1)), today.atStartOfDay(ZoneId.of(tz2)));
}
static String formatDuration(Duration duration) {
long hours = duration.toHours();
long minutes = duration.toMinutes() % 60;
String symbol = hours < 0 || minutes < 0 ? "-" : "+";
return String.format(symbol + "%02d:%02d", Math.abs(hours), Math.abs(minutes));
// ####################################Java-9####################################
// return String.format(symbol + "%02d:%02d", Math.abs(duration.toHoursPart()),
// Math.abs(duration.toMinutesPart()));
// ####################################Java-9####################################
}
}
Output:
+09:30
-09:30
+09:30
2021-03-24T19:52:29.474858+09:30
Learn more about the modern date-time API from Trail: Date Time.
Note that the java.util date-time API is outdated and error-prone. It is recommended to stop using it completely and switch to the modern date-time API*.
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. 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 and How to use ThreeTenABP in Android Project.
TimeZone has two methods getRawOffet and getOffset that retrieves the offset of the time zone to UTC in milliseconds. The second one is adjusted for Daylight Saving Time and request the date to check if it is in effect.
TimeZone current = TimeZone.getDefault();
TimeZone db = TimeZone.getTimeZone("US/Eastern"); // or "EST5EDT", or "America/New_York"
System.out.printf("DB: %s Current: %s\n", db, current);
System.out.printf("Raw: %.1f h\n", (db.getRawOffset() - current.getRawOffset())/3_600_000D);
final long now = System.currentTimeMillis();
System.out.printf("DST: %.1f h\n", (db.getOffset(now) - current.getOffset(now))/3_600_000D);