Consider the below code:
if(strTimeZoneCd.equals("A"))
locTz = TimeZone.getTimeZone("AST");
else if(strTimeZoneCd.equals("M"))
locTz = TimeZone.getTimeZone("MST");
else if(strTimeZoneCd.equals("P"))
locTz = TimeZone.getTimeZone("PST");
else if(strTimeZoneCd.equals("H"))
locTz = TimeZone.getTimeZone("HST");
else if(strTimeZoneCd.equals("C"))
locTz = TimeZone.getTimeZone("CST");
else if(strTimeZoneCd.equals("E"))
locTz = TimeZone.getTimeZone("EST");
else if(strTimeZoneCd.equals("G"))
locTz = TimeZone.getTimeZone("GMT");
else if(strTimeZoneCd.equals("Y"))
locTz = TimeZone.getTimeZone("AKST");
Here if I am passing A, it will give me AST. But instead of that I need to determine if I should return AST or ADT.
I need to determine if AST is under daylight saving now. If it is under daylight saving, I can return ADT and if it is not I can return AST. But I am not getting how to determine whether that timezone is under daylight saving or not.
Can someone please help me?
First of all, avoid using the short abbreviations for timezones names (like CST, PST or CEST) because they are ambiguous and not standard.
CST, for example, is used by more than one timezone: it can be "Central Standard Time", "China Standard Time" or "Cuba Standard Time". And each one has different rules regarding Dayligh Saving Time, so using the abbreviation might not necessarily get the results you expect.
The TimeZone class assumes some defaults for those short names (all arbitrary choices, as any default is) and also has the bizarre behaviour of returning GMT when the name is unknown.
To avoid those ambiguities, it's better to use IANA timezones names (always in the format Region/City, like Asia/Kolkata or America/New_York).
You can get a list of available timezones (and choose the one that fits best your system) by calling TimeZone.getAvailableIDs().
Then you can use the inDaylightTime() method, as already explained in the other answers.
Another alternative is to use a formatter, because it checks automatically if it's in Daylight Saving Time and prints the zone short name. I also use a java.util.Locale to indicate that the names should be in English (I'm not sure if different languages affect the short zone names, it's a "just in case" approach):
// formatter with `z` (zone short name)
SimpleDateFormat sdf = new SimpleDateFormat("z", Locale.ENGLISH);
// set timezone in the formatter
sdf.setTimeZone(TimeZone.getTimeZone("America/New_York"));
// prints the zone name for the current date
System.out.println(sdf.format(new Date()));
The code above prints EDT (because today, September 13th 2017, New York is in Daylight Saving Time and the abbreviation used is EDT).
In this case, you could create the formatter, and use your if logic to set the correct timezone in it. Then, the formatter takes care of checking if the date is in Daylight Saving Time, returning the correct abbreviation.
Java new Date/Time API
The old classes (Date, Calendar and SimpleDateFormat) have lots of problems and design issues, and they're being replaced by the new APIs.
If you're using Java 8, consider using the new java.time API. It's easier, less bugged and less error-prone than the old APIs.
If you're using Java <= 7, you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes. And for Android, you'll also need the ThreeTenABP (more on how to use it here).
The code below works for both.
The only difference is the package names (in Java 8 is java.time and in ThreeTen Backport (or Android's ThreeTenABP) is org.threeten.bp), but the classes and methods names are the same.
First I create a DateTimeFormatter with the z pattern (that corresponds to zone short name) and English locale.
Then I use a ZonedDateTime, which represents a date and time in a specific timezone, and the now() method to get the current date/time. I also use ZoneId to especify the timezone I want:
// create formatter for short zone name and English locale
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("z", Locale.ENGLISH);
// format current date in New York timezone
System.out.println(fmt.format(ZonedDateTime.now(ZoneId.of("America/New_York"))));
This also prints EDT as well. You could apply the same if logic above to define which timezone will be used in ZoneId.of(). Just remind to not use the short names (CST, etc), because the new API is not so lenient as the old one.
TimeZone assumes lots of arbitrary defaults and returns "GMT" when the zone doesn't exist, but ZoneId will throw an exception if you try to get an invalid zone (some abbreviations should work for retro-compatibility reasons, but the defaults are arbitrary as well, and you should avoid them).
Custom map of zone names
You can optionally create a custom map of timezone names, so you don't need to make lots of if clauses to determine the corresponding zone. Something like this:
// create custom map of zone names
Map<String, String> customZones = new HashMap<>();
// map "E" to New York
customZones.put("E", "America/New_York");
// map "G" to GMT
customZones.put("G", "GMT");
...
// create timezone using the custom map ("E" will create "America/New_York" zone)
ZoneId zone = ZoneId.of("E", customZones);
// format current date in specified timezone
System.out.println(fmt.format(ZonedDateTime.now(zone)));
work around this:
For any particular TimeZone
TimeZone tz = TimeZone.getTimeZone("EST");
boolean inDs = tz.inDaylightTime(new Date());
You can use this program to determine whether that timezone is under day light saving or not.
Also see this link.
TimeZone.getTimeZone("CST") returns GMT
import java.util.Date;
import java.util.TimeZone;
public class test {
public static void main(String[] args) {
System.out.println(TimeZone.getTimeZone("EST").inDaylightTime( new Date() ));
System.out.println(TimeZone.getTimeZone( "GMT-9:00").inDaylightTime( new Date() ));
}
}
Related
If I take current date from my application, it comes with variation like below:
scenario 1: when the date is less than 10th of the month, a month is less than 10 of the year --> example: 5/9/18
scenario 2: when the date is >= 10th of the month, a month is less >= 10 of the year --> example: 10/11/18
Note: all the examples are in MM/DD/YY format and timezone is the USA
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DATE,-2);
DateFormat dateFormat = new SimpleDateFormat("MM/dd/yy HH:mm a");
String PastDate = dateFormat.format(cal.getTime());
info("Date is displayed as : "+ PastDate );
The above piece of code throwing me an error when the scenario 1 is in place. But if I format the date-time as "M/d/yy H:mm a" it works for both the scenario. I need the date add also.
Will it be a good practice to use the 2nd format? or there is any other way to get it done. Expert guidance please..
java.time
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT)
.withLocale(Locale.US);
ZonedDateTime dayBeforeYesterday = ZonedDateTime.now(ZoneId.of("America/St_Thomas"))
.minusDays(2);
System.out.println(dayBeforeYesterday.format(formatter));
Running just now I got this output:
5/7/18, 8:44 AM
Please specify your desired time zone where I put America/St_Thomas. Think twice before you use ZoneId.systemDefault() for your JVM’s time zone setting since this setting may be changed at any time from other parts of your program or other programs running in the same JVM; but if you trust the setting reflects the user’s time zone, it’s the correct thing to use.
Rather than defining your own output format prefer using one of the built-in formats you get from DateTimeFormatter.ofLocalizedDateTime. Do specify locale (no matter if you use a built-in format or roll your own). Again, use Locale.getDefault() if you trust the JVM’s setting is correct.
Avoid the old date and time classes like Calendar, DateFormat and SimpleDateFormat. They are not only long outdated, they are also poorly designed and the last two in particular notoriously troublesome. Today we have so much better in java.time, the modern Java date and time API.
Link: Oracle tutorial: Date Time explaining how to use java.time.
The number of characters in the format MM indicates that two digits are required in the input. A single character M will match one or two digits. Use M/d/yy H:mm a to support your desired formats.
I'm new to Java. I have a time I am getting from a web-page, this is in the "hh:mm" format (not 24 hour). This comes to me as a string. I then want to combine this string with todays date in order to make a Java Date I can use.
In C#:
string s = "5:45 PM";
DateTime d;
DateTime.TryParse(s, out d);
in Java I have attempted:
String s = "5:45 PM";
Date d = new Date(); // Which instantiates with the current date/time.
String[] arr = s.split(" ");
boolean isPm = arr[1].compareToIgnoreCase("PM") == 0;
arr = arr[0].split(":");
int hours = Integer.parseInt(arr[0]);
d.setHours(isPm ? hours + 12 : hours);
d.setMinutes(Integer.parseInt(arr[1]));
d.setSeconds(0);
Is there a better way to achieve what I want?
Is there a better way to achieve what I want?
Absolutely - in both .NET and in Java, in fact. In .NET I'd (in a biased way) recommend using Noda Time so you can represent just a time of day as a LocalTime, parsing precisely the pattern you expect.
In Java 8 you can do the same thing with java.time.LocalTime:
import java.time.*;
import java.time.format.*;
public class Test {
public static void main(String[] args) {
String text = "5:45 PM";
DateTimeFormatter format = DateTimeFormatter.ofPattern("h:mm a");
LocalTime time = LocalTime.parse(text, format);
System.out.println(time);
}
}
Once you've parsed the text you've got into an appropriate type, you can combine it with other types. For example, to get a ZonedDateTime in the system time zone, using today's date and the specified time of day, you might use:
ZonedDateTime zoned = ZonedDateTime.now().with(time);
That uses the system time zone and clock by default, making it hard to test - I'd recommend passing in a Clock for testability.
(The same sort of thing is available in Noda Time, but slightly differently. Let me know if you need details.)
I would strongly recommend against using java.util.Date, which just represents an instant in time and has an awful API.
The key points here are:
Parse the text with a well-specified format
Parse the text into a type that represents the information it conveys: a time of day
Combine that value with another value which should also be carefully specified (in terms of clock and time zone)
All of these will lead to clear, reliable, testable code. (And the existing .NET code doesn't meet any of those bullet points, IMO.)
To parse the time, you can do as explained in #Jon Skeet's answer:
String input = "5:45 PM";
DateTimeFormatter parser = DateTimeFormatter.ofPattern("h:mm a", Locale.ENGLISH);
LocalTime time = LocalTime.parse(input, parser);
Note that I also used a java.util.Locale because if you don't specify it, it'll use the system's default locale - and some locales can use different symbols for AM/PM field. Using an explicit locale avoids this corner-case (and the default locale can also be changed, even at runtime, so it's better to use an explicit one).
To combine with the today's date, you'll need a java.time.LocalDate (to get the date) and combine with the LocalTime, to get a LocalDateTime:
// combine with today's date
LocalDateTime combined = LocalDate.now().atTime(time);
Then you can format the LocalDateTime using another formatter:
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm");
System.out.println(combined.format(fmt));
The output is:
16/08/2017 17:45
If you want to convert the LocalDateTime to a java.util.Date, you must take care of some details.
A java.util.Date represents the number of milliseconds since 1970-01-01T00:00Z (aka Unix Epoch). It's an instant (a specific point in time). Check this article for more info.
So, the same Date object can represent different dates or times, depending on where you are: think that, right now, at this moment, everybody in the world are in the same instant (the same number of milliseconds since 1970-01-01T00:00Z), but the local date and time is different in each part of the world.
A LocalDateTime represents this concept of "local": it's a date (day, month and year) and a time (hour, minute, second and nanosecond), but without any relation to a specific timezone.
The same LocalDateTime object can represent different instants in time in different timezones. So, to convert it to a Date, you must define in what timezone you want it.
One option is to use the system's default timezone:
// convert to system's default timezone
ZonedDateTime atDefaultTimezone = combined.atZone(ZoneId.systemDefault());
// convert to java.util.Date
Date date = Date.from(atDefaultTimezone.toInstant());
But the default can vary from system/environment, and can also be changed, even at runtime. To not depend on that and have more control over it, you can use an explicit zone:
// convert to a specific timezone
ZonedDateTime zdt = combined.atZone(ZoneId.of("Europe/London"));
// convert to java.util.Date
Date date = Date.from(zdt.toInstant());
Note that I used Europe/London. The API uses IANA timezones names (always in the format Region/City, like America/Sao_Paulo or Europe/Berlin).
Avoid using the 3-letter abbreviations (like CST or PST) because they are ambiguous and not standard.
You can get a list of available timezones (and choose the one that fits best your system) by calling ZoneId.getAvailableZoneIds().
And there's also the corner cases of Daylight Saving Time (when a LocalDateTime can exist twice or can't exist due to overlaps and gaps). In this case, Jon's solution using ZonedDateTime avoids this problem).
I am making a diary application for Android and I want to allow the user to select the timezone they are in. Time has always been a area of confusion for me programatically.
I am going to create an enum for the available timezones.
I am going to save date/time entries to a sqlite in long UTC format, then handling offsets and DST programmatically in Java for display purposes.
I am actually aware of Java's limitations when it comes to date/time handling.
Calendar utc = Calendar.getInstance(TimeZone.getTimeZone("UTC")); //returns the current time in UTC format
Long utcLong = utc.getTimeInMillis(); //returns current utc time in long for database insertion
Question 1: How would I apply an offset to it and account for when to apply any additional DST offsets? Because not all timezones observe DST and DST comes into effect at different dates for different timezones.
Question 2: Java's TimeZone class has something like ~800 ids, it would be annoying to the user to have to scroll through ~800 options to find the one that applys to them. Is there a short list available? I'm thinking there are around ~50 useful timezones.
First of all, I recommend you to not use the Calendar class. It's outdated and has lots of bugs and design issues. This terrible API was replaced by much better ones:
for Java >= 8, use the new date-time API
for Java <= 7, use the ThreeTen Backport
for Android, you can also try ThreeTenABP
The code below works for all, the only difference is the package names (in Java 8 is java.time and in ThreeTen Backport is org.threeten.bp), but the classes and methods names are the same.
To get the UTC current date/time, the best choice is to use Instant class:
// current date/time in UTC - now() always returns the current instant in UTC
Instant instant = Instant.now();
System.out.println(instant); // 2017-06-03T18:03:55.976Z
// equivalent to calendar.getTimeInMillis(), it returns a long
System.out.println(instant.toEpochMilli()); // 1496513035976
To convert this instant to a timezone, you can use the ZoneId with a ZonedDateTime:
// ZoneId accepts the same IDs used by TimeZone
ZoneId zone = ZoneId.of("America/Sao_Paulo");
// convert instant to timezone
ZonedDateTime z = instant.atZone(zone);
System.out.println(z); // 2017-06-03T15:03:55.976-03:00[America/Sao_Paulo]
// converts back to UTC (returns an Instant)
System.out.println(z.toInstant()); // 2017-06-03T18:03:55.976Z
The code above already takes care of DST changes, so the conversion from and to UTC is straightforward.
Timezone list
You say that you have a list of ~50 "useful" timezones. I don't know what criteria you used to define that list, but what happens if an user is in a timezone that's not in the list?
There are some ideas of timezone-picking user interfaces in this link and here. You can choose one and adapt to your app.
I also suggest to not use (if possible) the 3-letter timezone abbreviations (like CST or PST) because they are ambiguous and not standard. It's better to use the full names (like America/Sao_Paulo or Europe/London) as they are the ones used by Java's APIs (you can get the full list with ZoneId.getAvailableZoneIds()) and they are configured with all DST changes for each zone.
This question already has answers here:
How to check if a date Object equals yesterday?
(9 answers)
Closed 8 years ago.
I tried to convert the new today's date object to UTC. But no luck since new date object is always in local time zone. I have been trying to verify two dates using 'before' method. date1 is in UTC format. date2 is today.
The below code always prints the today's date object in local time zone.
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
public class test {
/**
* #param args
*/
public static void main(String[] args) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
String todayStr = sdf.format(new Date());// This string is in UTC. But I need date object in UTC.
try {
System.out.println(sdf.parse(todayStr));// This is still printing in local time zone.
} catch (ParseException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
A Date object isn't in any time zone - it's just a wrapper around the number of milliseconds since the Unix epoch. The Unix epoch is typically described in terms of UTC (namely midnight at the start of January 1st 1970) but it's really just a point in time.
To get the point in time 48 hours before "now", you can use something like:
Date earlier = new Date(System.currentTimeMillis() - TimeUnit.HOURS.toMillis(48));
You can compare that with any Date object to see which occurred earlier in time - again, with no reference to any particular time zone.
(This isn't an easily testable solution, admittedly - I prefer to abstract System.currentTimeMillis() behind a Clock interface, so that I can test with a fake clock set to whatever time I want.)
Unless you need a string representation, ignore it - as soon as you want a string representation, you need to think about both which calendar system and time zone you're interested in.
Note that you talk about "today's date" in the question - if you mean the start of a particular day, then the time zone is relevant, and you'll need to do more work.
Finally, I'd suggest that if you possibly can, you use either java.time.* from Java 8, or Joda Time instead of java.util.Date etc. The first two are both much better APIs than the last.
The below code always prints the today's date object in local time zone.
Yes, that's because Date.toString() uses the local time zone. That's just what it (unfortunately) does, and it doesn't mean that the Date object is "in" the local time zone.
See the correct answer by Jon Skeet for details.
Yesterday and Day Before
Your requirement is unclear, but it seems you want to test if the target date-time string represents a date-time that lies within the 48-hour period before the beginning of today as defined by UTC time zone. In other words, yesterday or day before.
Avoid java.util.Date
Avoid using the java.util.Date and .Calendar classes bundled with Java. They are notoriously troublesome. Instead use either Joda-Time or the new java.time in Java 8 (inspired by Joda-Time). Both libraries have a date-time class that knows its own assigned time zone, unlike java.util.Date.
Half-Open Span Of Time
And both libraries have classes to represent a span of time. Comparisons are done by the "Half-Open" approach where the beginning is inclusive and the ending exclusive. So your two-day period is defined as the first moment of day-before-yesterday (inclusive) and running up to, but not including, the first moment of today (exclusive).
ISO 8601
Your string format is defined by the ISO 8601 standard. Both Joda-Time and java.time use ISO 8601 for defaults in parsing and generating strings. So they have a built-in formatter to parse your string. Merely pass the string.
Immutable Objects
Joda-Time uses immutable objects. Rather than modify ("mutate") an existing object, a new object is instantiated with values based on the original. The reason is for thread-safety.
Joda-Time
Here is some example code in Joda-Time 2.4.
DateTime target = new DateTime( "2014-01-02T03:04:05.789Z", DateTimeZone.UTC );
DateTime nowUtc = DateTime.now( DateTimeZone.UTC );
DateTime today = nowUtc.withTimeAtStartOfDay();
DateTime dayBeforeYesterday = today.minusDays( 2 ).withTimeAtStartOfDay();
Interval interval = new Interval( dayBeforeYesterday, today ); // Half-Open.
boolean hit = interval.contains( target );
I am using java(IDE is eclipse) to query on mongodb. Below is my java code:
DBObject query = new BasicDBObject();
ObjectId id =new ObjectId("529f280b90ee58cb7732c2b8");
query.put("_id", id);
DBCursor cursor = collection.find(query);
while(cursor.hasNext()) {
DBObject object = (DBObject)(cursor.next());
System.out.println(object.get("_id"));
System.out.println(object.get("createDate"));
}
Problems happened in the createDate whose type is ISODate and value is ISODate("2013-10-21T01:34:04.808Z"), but the println result of my code is 'Mon Oct 21 **09**:34:04 CST 2013', the hour has changed from 01 to 09. I don't know what happened!
Can anybody help?
The hour did not change. You must be in China, given the "CST" in your example and the 8 hour difference. If you interpret "CST" as "China Standard Time" (rather than Central Standard Time in the US), then you have a time zone that is 8 hours ahead of UTC/GMT. So when ti is 1 AM UTC/GMT, at the vary same moment the clock on the wall in Taipei will read "9 AM".
Minor point: Those three-letter codes for time zones are obsolete and should be avoided. They are neither standardized nor unique. Use proper time zone names.
Major point: The problem lies in how you extract a value from MongoDB that represents a date-time.
I don't know MongoDB, and their doc is confusing, so I can't help you much further. If you can retrieve an ISO 8601 string as seen in your first example, that is much preferable to the format of your second example.
If you want to work with the date-time value in Java, you can feed an ISO 8601 string directly to a DateTime constructor in Joda-Time 2.3.
DateTime dateTime = new DateTime( "2013-10-21T01:34:04.808Z" );
Update
This doc says that the Java driver for MongoDB will give you a java.util.Date object. That explains your problem. The java.util.Date & Calendar classes bundled with Java are notoriously bad. One problem is that while a Date instance has no time zone, its toString() method uses the JVM's default time zone to render a string. And Date's toString method uses that terrible ambiguous format.
You should avoid using java.util.Date & Calendar classes. For now use the Joda-Time library. In Java 8, you can use the new java.time.* classes.
You can convert back and forth between java.util.Date and Joda-Time. Pass a Date instance to Joda-Time constructor. To go back, call Joda-Time toDate() format.
Note that while a java.util.Date has no time zone information within it, in contrast a DateTime object does have a time zone assigned. If you want UTC/GMT, specify DateTimeZone.UTC.
Your code should look more like:
java.util.Date date = object.get("createDate");
DateTime createDateTime = new DateTime( date, DateTimeZone.forId( "Asia/Manila" ) );
System.out.println( createDateTime );
… do some work …
java.util.Date dateGoingBackToMongoDB = createDateTime.toDate();