How to convert a String contains timestamp with offset - java

I have a String contains date and time like below :
String test = ""20220215160000Z-0400";
The correct value that I need to print out is :
Date = 02/15/2022
Time = 12:00
The time is basically the 16:00 - 4 hours in the offset. I couldn't figure out how to do it. Any helps will be appreciated. Currently, my codes is like below :
DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss'Z'");
Date parsedDate = dateFormat.parse(test);
Timestamp timeStamp = new Timestamp(parsedDate.getTime());
System.out.println(timeStamp.toString());
And the print out is : 2022-02-15 16:00:00.0
I need the value to be 2022-02-15 12:00:00.0

using java.time api(you can change it to java easily):
var str = "20220215160000Z-0400"
var formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss'Z'Z")
var zonedDate = ZonedDateTime.parse(str, formatter)
println(zonedDate.offset)
var offsetTime = zonedDate.toOffsetDateTime().withOffsetSameInstant(ZoneOffset.of("-0800"))
var for2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
println(for2.format(offsetTime))
notice i'm using ZoneOffset.of("-0800") instead of ZoneOffset.of("-0000")

Your date format is quite strange: as it does not reflect local time but UTC time, "20220215160000Z-0400" is normally regarded as local time (UTC-4) = 1600 HRS, but based on your explanation you'd like it such that UTC time = 1600 HRS, and therefore local time is 1200 HRS.
This means you need to have a "fix" on the date. See the sample code below:
String test = "20220215160000Z-0400";
ZoneId desiredZone = ZoneOffset.of("-0400");
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss'Z'Z");
LocalDateTime localDateTime = LocalDateTime.parse(test, formatter);
ZonedDateTime min4HrsZonedDateTime = ZonedDateTime.of(localDateTime, desiredZone);
ZonedDateTime min4HrsZonedDateTimeFix = min4HrsZonedDateTime.withZoneSameLocal(ZoneOffset.UTC).withZoneSameInstant(desiredZone);
System.out.println("timestamp = " +Timestamp.from(min4HrsZonedDateTimeFix.withZoneSameLocal(ZoneOffset.systemDefault()).toInstant()));
I converted the time back to UTC but without using timezone, hence the min4HrsZonedDateTimeFix

Related

What is the correct way to format a date string to m/d/yyyy from "2020-05-08T11:01:48.3300000Z" datetime string in java/ Kotlin

I am trying to format a DateTime string that is received from the server. I have used the below formats and none is working - AppConstants.API_DATE_TIME_FORMAT =
- `"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"`
- `"yyyy-MM-dd'T'HH:mm:ss.SSSZ'Z'"`
- `"yyyy-MM-dd'T'HH:mm:ss.SSSZ"`
- `"yyyy-MM-dd'T'HH:mm:ss.SSSXX'Z'"`
- `"yyyy-MM-dd'T'hh:mm:ss.SSSSSS'Z'"`
and -
fun getFormattedDate(apiFormatDateTime: String): String {
return try{
val parser = SimpleDateFormat(AppConstants.API_DATE_TIME_FORMAT, Locale.getDefault())
val formatter = SimpleDateFormat(AppConstants.UI_DATE_FORMAT, Locale.getDefault())
val date = parser.parse(apiFormatDateTime)!!
formatter.format(date)
}catch (ex : Exception){
apiFormatDateTime
}
}
This works
String d="2020-05-08T11:01:48.3300000Z";
DateFormat originalFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSSS'Z'");
DateFormat targetFormat = new SimpleDateFormat("yyyyMMdd");
Date date = originalFormat.parse(d);
String formattedDate = targetFormat.format(date);
System.out.println("date==>"+formattedDate);
Output::
date==>20200508
java.time
I recommend that you use java.time, the modern Java date and time API, for your date and time work. In Java (because this is what I can write):
ZoneId zone = ZoneId.of("Asia/Kolkata");
DateTimeFormatter uiDateFormatter = DateTimeFormatter.ofPattern("M/d/uuuu");
String isoF8601ormatDateTime = "2020-05-08T11:01:48.3300000Z";
Instant time = Instant.parse(isoF8601ormatDateTime);
String uiString = time.atZone(zone)
.format(uiDateFormatter);
System.out.println(uiString);
Output is:
5/8/2020
Points to note:
The format from your API is ISO 8601. The classes of java.time parse the most common ISO 8601 variants as their default, that is, we need not specify any formatter.
My code also converts the date to the user’s time zone before formatting. Most users will expect this. Please put your user’s time zone where I put Asia/Kolkata.
Bonus info: to format the time, in the user’s time zone too:
DateTimeFormatter uiTimeFormatter
= DateTimeFormatter.ofPattern("hh:mm:ss a", Locale.ENGLISH);
String uiTimeString = time.atZone(zone).format(uiTimeFormatter);
System.out.println(uiTimeString);
04:31:48 PM
What went wrong in your attemtps?
There exists no way that SimpleDateFormat can parse 7 decimals on the seconds correctly. It only supports milliseconds, exactly three decimals. SimpleDateFormat takes 3300000 to be milliseconds, that is 3300 seconds or nearly an hour, which it adds to the time parsed.
Z in your incoming string is a UTC offset (of zero) and needs to be parsed as such, or you will get an incorrect result.
Z without quotes will parse an offset like +0000, but not Z. XX will parse Z, but that attempt failed because you additionally required (one more) Z after the Z.
You did not convert to the user’s time zone before formatting.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Wikipedia article: ISO 8601
You could try using LocalDateTime and DateTimeFormatter
String str = "1986-04-08 12:30";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
LocalDateTime dateTime = LocalDateTime.parse(str, formatter);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
LocalDateTime dateTime = LocalDateTime.of(1986, Month.APRIL, 8, 12, 30);
String formattedDateTime = dateTime.format(formatter); // "1986-04-08 12:30"
credit to :https://stackoverflow.com/a/22463063/9297896
You can try it like below
try {
XMLGregorianCalendar dt = DatatypeFactory.newInstance().newXMLGregorianCalendar("2020-05-13T12:12:12.123456Z");
String dateValue = new SimpleDateFormat("MM/dd/yyyy").format(dt.toGregorianCalendar().getTime());
System.out.println("datevalue="+dateValue);
} catch (DatatypeConfigurationException e) {
e.printStackTrace();
}
output: datevalue=05/13/2020
Here is how I did it for getting date and time from UTC format -
const val API_DATE_TIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSS'Z'"
const val UI_DATE_FORMAT = "MM/dd/yyyy"
const val UI_TIME_FORMAT = "hh:mm:ss a"
/**
* Function for getting date from api datetime string
* #return formatted time
*/
fun getFormattedDate(apiFormatDateTime: String): String {
return try{
val parser = SimpleDateFormat(AppConstants.API_DATE_TIME_FORMAT, Locale.getDefault())
parser.timeZone = TimeZone.getTimeZone("UTC")
val formatter = SimpleDateFormat(AppConstants.UI_DATE_FORMAT, Locale.getDefault())
val date = parser.parse(apiFormatDateTime)!!
formatter.timeZone = TimeZone.getDefault()
formatter.format(date)
}catch (ex : Exception){
apiFormatDateTime
}
}
/**
* Function for getting time from api datetime string
* #return formatted time
*/
fun getFormattedTime(apiFormatDateTime: String): String {
return try{
val parser = SimpleDateFormat(AppConstants.API_DATE_TIME_FORMAT, Locale.getDefault())
parser.timeZone = TimeZone.getTimeZone("UTC")
val formatter = SimpleDateFormat(AppConstants.UI_TIME_FORMAT, Locale.getDefault())
formatter.timeZone = TimeZone.getDefault()
formatter.format(parser.parse(apiFormatDateTime)!!)
}catch (ex : Exception){
apiFormatDateTime
}
}

Date and time to UTC given timezone

i have the following string: 2019120610000100 which corresponds to 2019/12/06 at 10:00 +1.
How can I convert this to utc time, in this case 2019/12/06 09:00?
This string could also have a +2, +3 ... -1, -2 ... timezone so I must be able to convert other strings too.
The + or - sign is given in another instance however, if it can be useful, it can be added to the time and date string.
(The string could become 201912061000 +0100)
Right now I'm converting it manually splitting the string but I'm trying to find a way to make this safe as it gets tricky with hours and minutes like 00 that have to change the day, possibly the month and year.
This is what I have made so far:
hour -= hourOffset;
if(hour<0){
hour += 24
}
minutes -= minutesOffset;
if(minutes<0){
minutes += 60
}
When dealing with dates and times, it is usually better to not do string operations but use one of the many classes that extend java.time.temporal.Temporal from the java.time package - introduced with Java 8.
In your case, you want to use an OffsetDateTime, as your string represents exactly that: A date-time with an offset. Note, that a ZonedDateTime is not really appropriate here, because the offset information (e.g. "+01:00") is not enough to represent a whole timezone. Look at this SO question for more information.
To get an OffsetDateTime from a string, you must simply parse it.
Let's do it.
Step 1: Adjust your string to contain the offset sign (plus or minus).
String offsetSign = "+";
String datetimeString = "2019120610000100";
datetimeString = new StringBuilder(datetimeString).insert(datetimeString.length() - 4, offsetSign).toString();
Step 2: Parse that string to an OffsetDateTime object.
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMddHHmmZ");
OffsetDateTime odt = OffsetDateTime.parse(datetimeString, dtf);
Step 3: Convert that OffsetDateTime to UTC.
OffsetDateTime odtUTC = odt.withOffsetSameInstant(ZoneOffset.UTC);
Printing out those variables
System.out.println(datetimeString);
System.out.println(odt);
System.out.println(odtUTC);
will get you the following output:
201912061000+0100
2019-12-06T10:00+01:00
2019-12-06T09:00Z
You can directly convert the time to UTC by the following code
String dateStr = "201912061000+0100";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmm");
final LocalDateTime parse = LocalDateTime.parse(dateStr.substring(0, dateStr.length()-5), formatter);
final ZoneId zone = ZoneId.of("GMT"+dateStr.substring(12,15)+":"+dateStr.substring(15));
final ZonedDateTime given = ZonedDateTime.of(parse, zone);
final String toUTC = given.withZoneSameInstant(ZoneId.of("UTC"))
.format(DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm"));
String dateStr = "2019120610000100";
DateTimeFormatter dtfInput = DateTimeFormatter.ofPattern("yyyyMMddHHmm Z");
DateTimeFormatter dtfOutput = DateTimeFormatter.ofPattern("yyyy/MM/dd hh:mm");
String adjustedDateStr = new StringBuilder(dateStr).insert(dateStr.length() - 4, " +").toString();
ZonedDateTime givenDate = ZonedDateTime.parse(adjustedDateStr, dtfInput);
ZonedDateTime timezoneAdjustedDate = ZonedDateTime.ofInstant(givenDate.toInstant(), ZoneId.of("UTC"));
System.out.println(dtfOutput.format(timezoneAdjustedDate));
Since you handle the plus or minus for the timezone offset externally, you can just insert it into the exsample above instead of the plus if need be.

Convert milliseconds to timestamp with UTC

I'm trying to convert milliseconds to Timestamp with timezone UTC but it doesn't work as is expected because it convert to my localdatetime.
I have tried following. While debugging the code I have found that when execute this: new DateTime(eventDate) it is working properly because it's value is 10:34:18.721 but later new Timestamp() change it to localdatetime.
long eventDate = 1566297258721L;
DateTimeZone.setDefault(DateTimeZone.UTC);
Timestamp timestamp = new Timestamp(new DateTime(eventDate).getMillis());
I expect to output as:2019-08-20 10:34:18.721 but actual output is: 2019-08-20 12:34:18.721
You can use java.time package of Java 8 and later:
ZonedDateTime zonedDateTime = Instant.ofEpochMilli(1566817891743L).atZone(ZoneOffset.UTC);
I don't understand why you are creating a new DateTime and then get the milliseconds from there, if you already have the milliseconds in the beginning.
Maybe I'm misunderstanding your problem. The milliseconds have nothing to do with the timezone. The timezone is used to compare the same moment in 2 different places and get the respective date. Here are my solutions
If you want a timestamp from milliseconds:
long eventDate = 1566297258721L;
Timestamp time=new Timestamp(eventDate);
System.out.println(time);
The result would be 2019-08-20 10:34:18.721 , also the wished SQL format
If you want to convert a moment from a Timezone to another:
You will get the moment in your actual timezone and transform it in a different one in order to see e.g. what time it was in an other country
long eventDate = 1566297258721L;
Calendar calendar = Calendar.getInstance();
calendar.setTime(eventDate);
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
dateFormat.format(calendar.getTime());
I hope those snippets could be useful. Happy Programming!
You can try the following,
long eventDate = 1566297258721L;
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z", Locale.US);
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
String stringDate = simpleDateFormat.format(new Date(eventDate));
System.out.println(stringDate);
It gives me the following output.
2019-08-20 10:34:18 UTC

Subtract char of digits like normal integers

I have two strings which can be seen as time stamps:
String min="2017-04-15 13:27:31";
String max="2017-04-15 13:40:01";
Assume we want to find out the time passed from first time stamp to the second one. If there was only the time and no date included, I could get it using my following code:
String[] partsMin=min.split(":");
String[] partMax=max.split(":");
int diffZero=Integer.parseInt(partMax[0])-Integer.parseInt(partsMin[0]);
int diffOne=Integer.parseInt(partMax[1])-Integer.parseInt(partsMin[1]);
int diffOTwo=Integer.parseInt(partMax[2])-Integer.parseInt(partsMin[2]);
diffInSec=diffZero*3600+diffOne*60+diffOTwo;
So here is the question. How to get the job done while there is a date within the time stamp?
I would construct LocalDateTime instances from it.
Then i would get the milliseconds from it and substract startTime from EndTime.
What is remaining are the milliseconds passed between the two. A DateTimeFormatter is helpful as well for this purpose.
String strMin = "2017-04-15 13:27:31";
DateTimeFormatter formatterTime = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime dateTimeMin = LocalDateTime.parse(strMin, formatter);
String strMax = "2017-04-15 13:40:01";
LocalDateTime dateTimeMax = LocalDateTime.parse(strMax, formatter);
long minutes = ChronoUnit.MINUTES.between(dateMin, dateMaxto);
long hours = ChronoUnit.HOURS.between(dateMin, dateMax);
If you want to get the milliseconds:
long millisPassed = dateMax.toEpochMilli() - dateMax.toEpochMilli();
Use the java date time libraries (even the old Date class would be fine for this) to parse the string into a proper object.
Depending on the date time library you chose you can then look at the difference between them. The simplest would be something like:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
Date date1 = sdf.parse(str1);
Date date2 = sdf.parse(str2);
long differenceInSeconds = (date2.getTime()-date1.getTime())/1000;
The new Java 8 time classes would also allow you to do this and would be better to learn going forwards. I can't remember the syntax for that off the top of my head though.
Did you try with replace all the other part of your String like this :
String[] partsMin = min.replaceAll("\\d+-\\d+-\\d+", "").trim().split(":");
String[] partMax = max.replaceAll("\\d+-\\d+-\\d+", "").trim().split(":");
Doing this in your code:
int diffZero=Integer.parseInt(partMax[0])
is the same as doing:
int diffZero=Integer.parseInt("2017-04-15")
that is generating an Exception(NumberFormatException)
you should better try to PARSE those strings min and max into a date
Edit:
you can inspect your code/ variables: and see that splitting to ":" is not giving you back the correct array since the element at index 0 is holding more information than you need...
but as I said before, you are going on the wrong path, dont re invent the wheel and look how practical will get using the APIs that java has for us:
String min = "2017-04-15 13:27:31";
String max = "2017-04-15 13:40:01";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime dateTimeMin = LocalDateTime.parse(min, formatter);
LocalDateTime dateTimeMax = LocalDateTime.parse(max, formatter);
long days = ChronoUnit.DAYS.between(dateTimeMin, dateTimeMax);
long minutes = ChronoUnit.MINUTES.between(dateTimeMin, dateTimeMax);
System.out.println(days);
System.out.println(minutes);
use SimpleDateFormat to parse the date string, and do operation on Date result, you will get right value. This works well for date between '2017-02-28 23:59:59' and '2017-03-01 00:00:01'
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date1 = format.parse("2017-02-28 23:59:59");
Date date2 = format.parse("2017-03-01 00:00:01");
long time1 = date1.getTime();
long time2 = date2.getTime();
long diff = time2 - time2; // should be 2000

How do I get the date of 31 days ago?

How can I get x which should be 31 days before current_date?
x(date)___________________________current_date
31
Just subtract 31 days. For example:
LocalDate current = new LocalDate(2015, 6, 19);
LocalDate x = current.minusDays(31); // 2015-05-19
To get the current date, you could use:
LocalDate current = new LocalDate(); // Default time zone
or
LocalDate current = new LocalDate(zone); // Some specific zone
Or you may want to create your own "clock" representation which is able to give you the current Instant, in which case you'd use:
LocalDate current = clock.getCurrentInstant().toDateTime(zone).toLocalDate();
(That lets you use dependency injection to write simpler unit tests with a fake clock.)
You can try this:
LocalDate current = new LocalDate();//Constructs an instance set to the current local time evaluated using ISO chronology in the default zone.
LocalDate x = current.minusDays(31);
Or otherwise you can try:
LocalDate current = LocalDate.now();//Obtains a LocalDate set to the current system millisecond time using ISOChronology in the default time zone
LocalDate x = current.minusDays(31);
You can used JODA API if you want, its very advance and useful features:
String DATE_PATTERN = "dd/MM/yyyy";
DateTimeFormatter formatter = DateTimeFormat.forPattern(DATE_PATTERN);
String systemDate = formatter.print(DateTime.now());
System.out.println("Current Date : " + systemDate);
String newDate = formatter.print(DateTime.now().minusDays(31));
System.out.println("Date 31 days ago : " + newDate);
Output:
Current Date : 19/06/2015
Date 31 days ago : 19/05/2015

Categories

Resources