SimpleDateFormat missing time - java

I have a strange issue. The below code is executed in a while loop through a few times. Now, every so often, this sdf.parse returns 0s for the hours, minutes and seconds. An example of the dates look like this...
2014:3:7:8:0
2014:3:7:9:0
2014:3:7:10:0
2014:3:7:11:0
2014:3:7:12:0 * This returns 0's
2014:3:7:13:0
2014:3:7:14:0
Below is the code.
SimpleDateFormat sdf = new SimpleDateFormat("yyyy:M:d:h:m");
sdf.setTimeZone(TimeZone.getDefault());
Date sTime = null;
try {
sTime = sdf.parse(start);
} catch (ParseException e) {
e.printStackTrace();
return null;
}

I think 12 at hour position is getting read in 12h format, so it is the same as 0. Try H instead of h in pattern
SimpleDateFormat sdf = new SimpleDateFormat("yyyy:M:d:H:m");

'h' represents hour in 1-12 format. You should use 'H' (in upper case) instead if you want 0-23 format. Also you needn't explicitly set default time zone because by default it equals TimeZone.getDefault().

Related

Dateformatter in java [duplicate]

This question already has answers here:
SimpleDateFormat parsing date with 'Z' literal [duplicate]
(12 answers)
Closed 4 years ago.
I am using the below code to format millisecond resolution date strings. It works for 2018-09-14T13:05:21.329Z but not 2018-09-14T13:05:21.3Z. Can anybody suggest the reason and how to correct it?
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX");
SimpleDateFormat sdfDestination = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
Date parsedDate = formatter.parse(date);
String destDate = sdfDestination.format(parsedDate);
return destDate;
} catch (java.text.ParseException parseException) {
logger.error("Parse Exception occured while converting publication time to date "
+ "format 'yyyy-MM-dd HH:mm:ss'", parseException);
}
I get below exception:
java.text.ParseException: Unparseable date: "2018-09-14T13:05:21.3Z"
at java.text.DateFormat.parse(Unknown Source) ~[na:1.8.0_181]
at com.noordpool.api.implementation.utility.Utility.parseDate(Utility.java:136) [classes/:na]
at com.noordpool.api.implementation.utility.Utility.parseMessage(Utility.java:77) [classes/:na]
Your only problem is that you are using a wrong pattern for SimpleDateFormat, you need to change:
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX");
To:
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
Because the Z used in the date string means "zero hour offset" so you just need to pass it as 'Z' in your pattern.
This is a working demo with the right pattern.
Edit:
And to make things work with different Locales and Timezones, you need to use the appropriate Locale when you are creating the SimpleDateFormat instance, this is how should be the code:
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);
The only possible issue I can see is that you're passing in milliseconds incorrectly and the program doesn't know what to do about it.
So the last part of the formatter indicates with milliseconds and a timezone as .SSSX
But how does it evaluate 3Z for the input into this? I mean, do you say it's 300 timezone Z, or say it's 003 timezone Z, or worse, try and parse it as 3Z, which hopefully you see that you cannot turn '3Z' into a number.
To remedy this, I'd validate your input 'date' and ensure the milliseconds part is always 3 digits long, this removes the ambiguity and the program always knows that you mean '300 milliseconds, timezone Z'.
There is a problem in java 8 where the number of characters that you specified with the formatter should be an exact match (which is not specified in the documentation).
You can use three different Formatters and use nested exception as follows:
DateFormat format1 = new SimpleDateFormat("y-M-d'T'H:m:s.SX");
DateFormat format2 = new SimpleDateFormat("y-M-d'T'H:m:s.SSX");
DateFormat format3 = new SimpleDateFormat("y-M-d'T'H:m:s.SSSX");
Date parsedDate;
try {
// Parsing for the case - 2018-09-14T13:05:21.3Z
parsedDate = format1.parse(date);
} catch (ParseException e1) {
try {
// Parsing for the case - 2018-09-14T13:05:21.32Z
parsedDate = format2.parse(date);
} catch (ParseException e2) {
try {
// Parsing for the case - 2018-09-14T13:05:21.329Z
parsedDate = format3.parse(date);
} catch (ParseException e2) {
//The input date format is wrong
logger.error("Wrong format for date - " + date);
}
}
}
java.time
DateTimeFormatter dtfDestination
= DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss");
String date = "2018-09-14T13:05:21.3Z";
String destDate = Instant.parse(date)
.atZone(ZoneId.of("Indian/Comoro"))
.format(dtfDestination);
System.out.println(destDate);
Output from this snippet is:
2018-09-14 16:05:21
Please substitute your correct time zone if it didn’t happen to be Indian/Comoro, since correct output depends on using the correct time zone. If you want to use your JVM’s default time zone, specify ZoneId.systemDefault(), but be aware that the default can be changed at any time from other parts of your program or other programs running in the same JVM.
I am exploiting the fact that your string, "2018-09-14T13:05:21.3Z", is in ISO 8601 format, the format that the classes of java.time parse as their default, that is, without any explicit formatter. Instant.parse accepts anything from 0 through 9 decimals on the seconds, so there is no problem giving it a string with just 1 decimal, as you did. In comparison there is no way that an old-fashioned SimpleDateFormat can parse 1 decimal on the seconds with full precision since it takes pattern letter (uppercase) S to mean milliseconds, so .3 will be parsed as 3 milliseconds, not 3 tenths of a second, as it means.
Jahnavi Paliwal has already correctly diagnosed and explained the reason for the exception you got.
The date-time classes that you used, DateFormat, SimpleDateFormat and Date, are all long outdated and SimpleDateFormat in particular is notoriously troublesome. Since you seem to be using Java 8 (and even if you didn’t), I suggest you avoid those classes completely and use java.time instead.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Wikipedia article: ISO 8601

Display and save only hours in int

How to display only hours and using int variable? I mean print time like 20:30:44 PM, I want to store only hours, mean 20 in int variable. how to do that?
Can anybody tell me the code if you know, thanks?
Try using Calendar's get method like:
Calendar c = ..
c.setTime(...);//if you have time in long coming from somewhere else
int hour = c.get(Calendar.HOUR_OF_DAY);
If you try to parse time from String I recommend these solutions:
String time = "20:30:44 PM"; // this is your input string
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss aa");
try {
Date date = sdf.parse(time);
// this is the uglier solution
System.out.println("The hour is: "+date.getHours());
GregorianCalendar gc = new GregorianCalendar();
gc.setTime(date);
// this is nicer solution
System.out.println("The hour is: "+gc.get(Calendar.HOUR_OF_DAY));
} catch (ParseException e) {
System.err.println("Couldn't parse string! "+e.getMessage());
}
date.getHours() and gc.get(Calendar.HOUR_OF_DAY) return int, in this example I printed it out without creating variable.
You can, of course, use regular expression to find out hour in your string but above solutions should do the trick. You can learn more about SimpleDateFormat and available patterns here. I hope I helped you a bit.
EDIT: In his comment autor noted, that date isn't static (like in String) but dynamic:
Calendar calendar = new GregorianCalendar();
int hour = calendar.get(Calendar.HOUR_OF_DAY);
System.out.println("The hour is: "+hour);
I hope this helps.

How to check date(getting from json file) is before or after in android?

I am getting a date from JSON file, and it is in string format.I have two string values of date named startdate and enddate that is coming from intent to currentActivity. Now I want to check that, if date value coming from json file is after the startdate or before the enddate. How can I do this? And yes, the format I json file having is "yyyy-mm-dd".
JSON Data Look like:
{"posts":[{"start_date":"2013-02-15","end_date":"2013-02-21"}]}
Here is the code I have tried but I am getting output as Mon Jan 07 00:00:00 GMT+5:30 2013:
Intent intent = getIntent();
String startDate = intent.getStringExtra("startDate"); //I have check this. It is proper.
String endDate = intent.getStringExtra("endDate"); //I have check this. It is proper.
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date start = null,end = null;
try {
start = sdf.parse(startDate);
end = sdf.parse(endDate);
} catch (ParseException e1) {
e1.printStackTrace();
}
Here is the code of comparing date:
Date date = null;
try {
date = sdf.parse(c.getString(TAG_DATE)); //I am getting the date from a json file here.
} catch (ParseException e) {
e.printStackTrace();
}
Date currDate = new Date();
if (end.compareTo(currDate) < 0 || start.compareTo(currDate) < 0) {
Toast.makeText(getApplicationContext(),"Please select valid dates...",Toast.LENGTH_SHORT).show();
} else if (end.compareTo(currDate) == 0 && start.compareTo(currDate) >= 0){
if (date.after(start)) {
Toast.makeText(getApplicationContext(), "After...",Toast.LENGTH_SHORT).show();
}
} else if (end.compareTo(currDate) > 0 && start.compareTo(currDate) >= 0) {
if (date.after(start) && date.before(end)) {
Toast.makeText(getApplicationContext(),"Before...",Toast.LENGTH_SHORT).show();
}
}
I would prefer using a more robust approach that involves converting the date strings to actual Date (or Calendar) objects:
String startDateString = ...; // get date string from json
String endDateString = ...; // get date string from json
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
Date start = formatter.parse(startDateString);
Date end = formatter.parse(endDateString);
From here on, you can use e.g. start.before(end) or end.after(start) to check whether a date comes before or after another date. If you need more fine-grained control, you can always get the date in milliseconds and have your logic work on that.
So you've updated your code, but you're leaving it up to us to figure out what's going on and, more importantly, what you're expecting to happen? It looks like you want to check how the current date relates to those retrieved from json, although I'm a little lost at what the fourth date field, named date, is for.
Just some remarks about the current snippet:
if (end.compareTo(currDate) < 0 || start.compareTo(currDate) < 0)
Personally, I find before() and after() much more readable and descriptive, but I suppose there's nothing wrong with using compareTo(). However, important to realize is that 0 will only be returned iff the underlying millisecond representations of two dates are equal. With that being said, I'm not sure how much sense it would make to do the first check in the following condition:
else if (end.compareTo(currDate) == 0 && start.compareTo(currDate) >= 0)
You'll have to be really lucky to get the milliseconds of end exactly identical to currDate. Unless you do some manipulation somewhere to normalize all the dates to e.g. midnight, it's unlikely end.compareTo(currDate) == 0 will ever be true.
Regarding this normalization: have a look at the previously mentioned Calendar class. It'll allow you to easily retrieve the values for the separate fields of a datestamp/timestamp. For example, if you only want to compare the day, month and year, you can get those specific fields from a Calendar instance with a simple get call. Even more convenient is that you can also set every field independently - that's great for normalizing all dates to e.g. midnight or midday, after which you can still use the before() and after() methods.
I'm convinced that should give you enough pointers to correctly code up an implementation that fits your needs. Without exactly knowing what you're trying to achieve, I'm afraid I can't help you any further.
You can also try this:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
boolean isBefore = new Date().before(sdf.parse("2013-02-15",0));
http://developer.android.com/reference/java/text/SimpleDateFormat.html
http://developer.android.com/reference/java/util/Date.html
If you explode the date by dash - it will be easy to compare dates between mobile date and date by json. with easy compare logic you will get it.
String date = "2013-02-15";
String[] separated = date.split("-");
separated[0]; // this will contain "2013"
separated[1]; // this will contain "02"
separated[2]; // this will contain "15"
Calendar c1 = Calendar.getInstance();
String date = c1.get(Calendar.DAY_OF_MONTH);
Calendar ( to get mobile date )
http://developer.android.com/reference/java/util/Calendar.html

Issue with java DateFormat

Following is a piece of code that I am running.
#Test
public void testMyMehotd() {
String expected = "2012-09-12T20:13:47.796327Z";
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSS'Z'");
//df.setTimeZone(TimeZone.getTimeZone("UTC"));
Date d = null;
try {
d = df.parse(expected);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return;
}
String actual = df.format(d);
System.out.println(expected);
System.out.println(actual);
}
but the output is different than what I expect.
expected : 2012-09-12T20:13:47.796327Z
actual : 2012-09-12T20:27:03.000327Z
Can someone tell me the reason for this and what is the solution.
Thanks in advance.
Whenever you exceed 999 milliseconds, DateFormat will try to add the remaining milliseconds to your date. Consider the following simpler example:
String expected = "2012-09-12T20:13:47.1001Z";
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSS'Z'");
Date d = df.parse(expected);
The resulting date will be 2012-09-12T20:13:48.0001. That is, since you have 1001 milliseconds, you get 1 extra second (1000 milliseconds), and 1 millisecond (1001 % 1000). Thus instead of 47 seconds as in the original date, you get 48 seconds.
This is also what happens if you try to parse a date with an invalid number of days in a month. For example, if you try to add an extra day to September, and parse 2012-09-31:
String expected = "2012-09-31";
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
Date d = df.parse(expected);
System.out.println(df.format(d));
You'll actually get 2012-10-01. Again, that's because DateFormat will detect that the 31st day of September is not valid, and will try to use heuristics to transform the Date, thus adding one day, ending up with the first day of the next month.
There's an option to tell the parser not to use these heuristics, by setting lenient mode to false with:
df.setLenient(false);
However, using this mode, both above examples will throw a ParseException.
S means millisecond and you passed 796327 milliseconds. That number is equal to 13[min]:16[sec]:327[millis] so additional minutes and seconds ware added to your date.

Android Convert Central Time to Local Time

I have a MySql database that stores a timestamp for each record I insert. I pull that timestamp into my Android application as a string. My database is located on a server that has a TimeZone of CST. I want to convert that CST timestamp to the Android device's local time.
Can someone help with this?
Use getTimeZone.getDefault combined with according to the Android documentation.
public static synchronized TimeZone
getDefault ()
Gets the default time zone. Returns
the default time zone.
So since you know that CST is -6:00 from GMT, and you get a local timezone saying the user is +9:00 (Japan), you'd know to adjust your MySQL DB times by +15 hours (9 - (-6)). Or if they are in Miami (EST, -5), you would adjust by adding one hour (-5 - (-6)). If the are in Portland, Oregon, (PST -8), you would subtract 2 hours (-8 -(-6)).
So really you just need to get the local timezone offset and feed it into the basic equation: TimeZone.getDefault + 6 and you'll know what to add or subtract to your local DB. (+6 since -(-6) always works out to +6).
If I knew the first thing about writing Java, I'd go the extra step and write a bit of sample code, but alas, I'm only smart enough for scripts.
Crude Attempt at Java
I already said I have no idea how to do Java or object oriented anything, right?
Here's a crude attempt from just poking around the Android documentation. Any fine points or simple "Not even close" remarks welcome. Bear in mind that I figured out the right method and class already just from a quick search and I came up with a simple equation for converting the timezone offset for anywhere to CST, so I'm not a dunce, just someone who doesn't know when to leave well enough alone. Anyway, crude attempt:
System now = System.currentTimeMillis (); //Gets current local time in ms
TimeZone local_tz = TimeZone.getDefault(); //Gets current local TZ of phone
tz_offset_gmt = local_tz.getOffset(now)/3600000; // Get Offset in ms, divide by 3600000
tz_offset_cst = tz_offset_gmt + 6; // add offset to 6 to get current TZ offset to CST.
Anywhere close to how to do this in java?
Suppose you have a string of date in CST, parse it with timezone CST and then format it with the default timezone on your android.
String s = "2011-01-01 12:00:00";
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
df.setTimeZone(TimeZone.getTimeZone("CST"));
Date timestamp = null;
try {
timestamp = df.parse(s);
df.setTimeZone(TimeZone.getDefault());
System.out.println(df.format(timestamp));
} catch (ParseException e) {
e.printStackTrace();
}
can't you simply convert the date with simpleDateFormat?
then you just define the structure of your incoming date like that (df) and transform it to the form you want (df):
private static DateFormat df = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z");
private static DateFormat df2 = new SimpleDateFormat("dd/MM/yyyy 'at' HH:mm");
public void setyourDate(String yourDate) {
Date date2;
yourDate = getyourDate() + "" + yourDate;
try {
date2 = df.parse(yourDate);
yourDate = df2.format(date2);
} catch (ParseException e) {
}
this.yourDate = yourDate;
}
does it make sense?
This is an old question, but I want to write my answer. Assume, the timestamp you get from SQL is like the following format: yyyy-MM-dd'T'HH:mm:ss
public static Date convertStringToDate(String strDate) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
sdf.setTimeZone(TimeZone.getTimeZone("CST"));
return sdf.parse(strDate);
}

Categories