is there a way to have a DateTimeFormatter like that
DateTimeFormatter.ofPattern("HH:mm")
and it should convert to a LocalDateTime and just zero out whats missing?
Actually on Joda there was DateTimeFormat which gave back a DateTime and not a exception. Is there any equivalent to that?
val formatter = org.joda.time.format.DateTimeFormat.forPattern(pattern)
formatter.parseDateTime(data).toDate
will always yield a real date no matter what the pattern is while on java8 it says its missing LocalDate.
Actually the pattern should be variable so that people could either insert HH:mm and dd.MM.yyyy and always get a LocalDateTime, that should be initalized / defaulted to 1970-01-01T00:00.
So doing:
// with pattern HH:mm
formatter.parse("00:00") should yield LocalDateTime.of(1970, 01, 01, 0, 0)
// with pattern YYYY-mm
formatter.parse("2016-11") should yield LocalDateTime.of(2016, 11, 01, 0, 0)
There are no built-in defaults. You have to provide the missing values.
// Parse HH:mm
LocalDateTime ldt1 = LocalTime.parse("12:34")
.atDate(LocalDate.of(1970, 1, 1));
System.out.println(ldt1); // Prints 1970-01-01T12:34
// Parse YYYY-mm
LocalDateTime ldt2 = YearMonth.parse("2016-11")
.atDay(1)
.atStartOfDay();
System.out.println(ldt2); // Prints 2016-11-01T00:00
Notice that you didn't even need a DateTimeFormatter for any of them.
UPDATE
If you must use DateTimeFormatter, then you can create one using DateTimeFormatterBuilder, where you can supply missing values using the parseDefaulting() method.
// Parse HH:mm
DateTimeFormatter formatter1 = new DateTimeFormatterBuilder()
.appendPattern("HH:mm") // other time fields default to 0, see "Resolving"
.parseDefaulting(ChronoField.EPOCH_DAY, 0) // short for 1970-01-01
.toFormatter();
LocalDateTime ldt1 = LocalDateTime.parse("12:34", formatter1);
System.out.println(ldt1); // Prints 1970-01-01T12:34
// Parse YYYY-mm
DateTimeFormatter formatter2 = new DateTimeFormatterBuilder()
.appendPattern("uuuu-MM")
.parseDefaulting(ChronoField.DAY_OF_MONTH, 1) // see resolveDate()
.parseDefaulting(ChronoField.NANO_OF_DAY, 0) // short for 00:00:00.000000000
.toFormatter();
LocalDateTime ldt2 = LocalDateTime.parse("2016-11", formatter2);
System.out.println(ldt2); // Prints 2016-11-01T00:00
As for which fields are required for successful parsing, see:
DateTimeFormatter - Resolving
IsoChronology.resolveDate()
Just in case this solution works for me but I doubt it's not a "generic" answer since I only needed LocalDateTime and its also scala:
object MyDate {
def parse(text: CharSequence, formatter: DateTimeFormatter): MyDate = new MyDate(formatter.parse(text))
}
class MyDate(accessor: TemporalAccessor) {
private[this] def getOrDefault(field: TemporalField, default: Int): Int = {
if (accessor.isSupported(field)) accessor.get(field) else default
}
def toLocalDateTime: LocalDateTime = {
val year: Int = getOrDefault(ChronoField.YEAR, 1970)
val month: Int = getOrDefault(ChronoField.MONTH_OF_YEAR, 1)
val day: Int = getOrDefault(ChronoField.DAY_OF_MONTH, 1)
val hour: Int = getOrDefault(ChronoField.HOUR_OF_DAY, 0)
val minute: Int = getOrDefault(ChronoField.MINUTE_OF_HOUR, 0)
LocalDateTime.of(year, month, day, hour, minute)
}
}
Related
I'm trying to convert date from API "2022-08-16T06:25:00.000" to HH:mm (6:25) but getting DateTimeParseException.
My code: ZonedDateTime.parse(it.time[0], DateTimeFormatter.ofPattern("HH:mm"))
"time": [
"2022-08-16T06:25:00.000",
"2022-08-16T07:40:00.000"
],
String dateTimeStr = "2022-08-16T06:25:00.000";
LocalDateTime dateTime = LocalDateTime.parse(dateTimeStr);
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("HH:mm");
String time = dateTime.format(fmt);
System.out.println(time);
or, if you want to use the time as an instance of LocalTime, you can get it by dateTime.toLocalTime()
You don't need to define any DateTimeFormatter in this situation.
use a LocalDateTime because the input String does not hold any information about the zone
don't use a DateTimeFormatter for parsing that only parses hour of day and minutes of hour, the String to be parsed just contains more information
Here's an example without any DateTimeFormatter explicitly defined (but it will use default ones for parsing, at least):
public static void main(String[] args) {
// example input
String fromApi = "2022-08-16T06:25:00.000";
// parse it to a LocalDateTime because there's no zone in the String
LocalDateTime localDateTime = LocalDateTime.parse(fromApi);
// extract the time-of-day part
LocalTime localTime = localDateTime.toLocalTime();
// and print its toString() implicitly
System.out.println(localTime);
}
Output: 06:25
The above code will produce output of the pattern HH:mm, which will have leading zeros at hours of day to always have a two-digit representation.
If you insist on single-digit hours of day, you will have to prepare a DateTimeFormatter, like in this alternative example:
public static void main(String[] args) {
// example input
String fromApi = "2022-08-16T06:25:00.000";
// parse it to a LocalDateTime because there's no zone in the String
LocalDateTime localDateTime = LocalDateTime.parse(fromApi);
// extract the time-of-day part
LocalTime localTime = localDateTime.toLocalTime();
// prepare a DateTimeFormatter that formats single-digit hours of day
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("H:mm");
// print the LocalTime formatted by that DateTimeFormatter
System.out.println(localTime.format(dtf));
}
Output this time: 6:25
The other answers use Java. Since you've added a [kotlin] tag, here is a Kotlin-based answer for the sake of completeness. In order to make it different to the Java answers, I'm using kotlinx.datetime, which is still at the experimental stage at version 0.4.0.
import kotlinx.datetime.LocalDateTime
fun main() {
println(LocalDateTime.parse("2022-08-16T06:25:00.000").time) // prints "06:25"
// If you want "6:25" you can format it yourself:
println(with(LocalDateTime.parse("2022-08-16T06:25:00.000")) {
"$hour:$minute"
})
}
How about different approach
String dateTimeStr = "2022-08-16T06:25:00.000";
Matcher m=Pattern.of("T(\\d{2}:\\d{2}):").matcher(dateTimeStr);
m.find();
System.out.println(m.group(1);; //should print 06:25
And yet another "alternative" answer. It relies on the fact that in an ISO-compliant date-time format, the time starts in the 11th position.
private static final int ISO_TIME_POS = 11;
....
String dateTimeStr = "2022-08-16T06:25:00.000";
String timeStr = dateTimeStr.substring(ISO_TIME_POS, ISO_TIME_POS + 5);
System.out.println(timeStr); // prints "06:25"
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
}
}
I just need to change month number to a month name...
I tried to put three M's instead of two, and it shows error.
I kinda know the problem but don't know how to fix it.
DateTimeFormatter formater = DateTimeFormatter.ofPattern("ddMMyyyy");
Person[] people = new Person[parts.length / 4];
int br = 0;
for (int i = 0; i < parts.length; i += 4) {
LocalDate datum = LocalDate.parse(parts[i + 2], formater);
people[br++] = new Person(parts[i], parts[i + 1],datum, parts[i + 3]);
}
Instead of "1988-05-05",
this "1988-May-05" ...
Following can be used for formatting the way you want:
DateTimeFormatter.ofPattern("yyyy-MM-dd").format(LocalDate.now()) //2019-02-04
DateTimeFormatter.ofPattern("yyyy-MMM-dd").format(LocalDate.now()) //2019-Feb-04
DateTimeFormatter.ofPattern("yyyy-MMMM-dd").format(LocalDate.now()) //2019-February-04
It looks like you've already parsed your date. To convert a LocalDate to the kind of string you'd like, you can use the following formatter:
LocalDate date = LocalDate.of(2018, 1, 1);
DateTimeFormatter out = new DateTimeFormatterBuilder()
.appendValue(ChronoField.YEAR, 4)
.appendLiteral('-')
.appendText(ChronoField.MONTH_OF_YEAR, TextStyle.SHORT)
.appendLiteral('-')
.appendValue(ChronoField.DAY_OF_MONTH, 2)
.toFormatter(Locale.UK); // or your locale
System.out.println(
out.format(date)
);
First you parse a String representation of a Date like this:
DateTimeFormatter formater = DateTimeFormatter.ofPattern("ddMMyyyy");
LocalDate datum = LocalDate.parse("04022019", formater);
Now if the parsing succeeded and you have a valid LocalDate object,
you can format it:
String date = datum.format(DateTimeFormatter.ofPattern("yyyy-MMM-dd"));
System.out.println(date);
will print
2019-Feb-04
Try:
int month=5;
String name = java.time.Month.values()[month-1].name();
It has also a getDisplayName method:
String name = java.time.Month.values()[month-1].getDisplayName(TextStyle.FULL, Locale.getDefault());
or(from commment)
String name =java.time.Month.of(month).getDisplayName(TextStyle.FULL, Locale.getDefault());`
(or something alike)
The LocalDate class also provides several getter methods to extract these values as shown below:
LocalDate currentDate = LocalDate.of(2019, 02, 04);
(OR)
LocalDate currentDate = LocalDate.now(); // 2019-02-04
DayOfWeek dayOfWeek = currentDate.getDayOfWeek(); // TUESDAY
int dom = currentDate.getDayOfMonth(); // 04
int doy = currentDate.getDayOfYear(); // 35
Month month = currentDate.getMonth(); // FEBRUARY
int year = currentDate.getYear(); // 2019
I have a Kotlin function to get the total number of weeks in a month
Code
fun getTotalWeeksInMonth(instant: Instant): Int {
val calendar = Calendar.getInstance()
calendar.time = Date.from(instant)
return calendar.getActualMaximum(Calendar.WEEK_OF_MONTH)
}
However this is using a mix of the old Java date/time APIs (Date and Calendar) and the new APIs (Instant)
How would I achieve the same result, using just the new APIs?
You can try something like this pair of lines:
YearMonth currentYearMonth =
YearMonth.now(
ZoneId.systemDefault()
)
;
int weeks =
currentYearMonth
.atEndOfMonth()
.get(
WeekFields.ISO.weekOfMonth()
)
;
You can evaluate the "week of month" of last day of this month, in java:
static int getTotalWeeksInMonth(Instant instant) {
LocalDate localDate = LocalDate.ofInstant(instant, ZoneId.systemDefault());
LocalDate lastDayOfMonth = localDate.withDayOfMonth(localDate.lengthOfMonth());
int lastWeekOfMonth = lastDayOfMonth.get(WeekFields.ISO.weekOfMonth());
return lastWeekOfMonth;
}
See if this fits you, be careful about what Zone you are actually passing, and about WeekFields.ISO, in some regions it may work fine, but in others it may not:
Instant now = Instant.now();
ZonedDateTime zonedNow = now.atZone(ZoneId.systemDefault());
ZonedDateTime monthEnd = zonedNow.with(TemporalAdjusters.lastDayOfMonth());
System.out.println(monthEnd.get(WeekFields.ISO.weekOfMonth()));
Having an Instant I would convert it to date first:
val date = LocalDateTime.ofInstant(instant, ZoneId.systemDefault())
Then go with either
YearMonth.from(date).atEndOfMonth().get(ChronoField.ALIGNED_WEEK_OF_MONTH)
or
YearMonth.from(date).atEndOfMonth().get(WeekFields.ISO.weekOfMonth())
Complete example:
fun getTotalWeeksInMonth(instant: Instant): Int {
val date = LocalDateTime.ofInstant(instant, ZoneId.systemDefault())
return YearMonth.from(date).atEndOfMonth().get(ChronoField.ALIGNED_WEEK_OF_MONTH)
}
I need to parse a date string which has the following format:
yyyy-MM-dd TTTTT. All pattern letters are the standard DateTimeFormatter letters, except for the TTTTT part, which is a seconds-of-day field.
As there is no pattern defined for such a field, I needed to come up with something else. My first thought was to try and parse the field as milli-of-day (A), but by using 5 A's my field is treated as the least significant characters which is... yeah, not what I want.
Is there any out-of-the box solution I could use or do I have to resort to some custom made solution (like ignoring the TTTTT field, parsing it manually and using LocalDateTime.plusSeconds() on the resulting date)?
In other words, how can I make the following test case pass?
public class DateTimeParserTest {
private static final String PATTERN = "yyyy-MM-dd TTTTT";
private static final DateTimeFormatter FORMATTER =
DateTimeFormatter.ofPattern(PATTERN);
#Test
public void testParseSecondsOfDay() throws Exception {
String input = "2016-01-01 86399";
LocalDateTime localDateTime = LocalDateTime.parse(input, FORMATTER);
assertEquals("2016-01-01T23:59:59", localDateTime.toString());
}
}
Based on your correction (leaving out the potentially ambivalent part "HH:mm") the Java-8-solution would look like:
private static final DateTimeFormatter FORMATTER =
new DateTimeFormatterBuilder()
.appendPattern("yyyy-MM-dd ")
.appendValue(ChronoField.SECOND_OF_DAY, 5)
.toFormatter();
well it may not be what what you are looking, but i hope it helps
private static final String PATTERN = "yyyy-MM-dd HH:mm:ss"; //MODIFICATION HERE
private static final DateTimeFormatter FORMATTER =
DateTimeFormatter.ofPattern(PATTERN);
#Test
public void testParseSecondsOfDay() throws Exception {
String input = "2016-01-01 00:00:86399";
int lastIndexOf = input.lastIndexOf(':');
CharSequence parsable = input.subSequence(0,lastIndexOf)+":00";
CharSequence TTTTPart = input.subSequence(lastIndexOf+1, input.length());
LocalDateTime localDateTime = LocalDateTime.parse(parsable, FORMATTER);
Calendar calendar = Calendar.getInstance(); // gets a calendar using the default time zone and locale.
calendar.set(
localDateTime.getYear(),
localDateTime.getMonth().ordinal(),
localDateTime.getDayOfMonth(),
localDateTime.getHour(),
localDateTime.getMinute(),
0);
calendar.add(Calendar.SECOND, Integer.parseInt(TTTTPart.toString()));
StringBuilder toParse = new StringBuilder();
toParse.append(calendar.get(Calendar.YEAR) /* It gives 2016 but you what 2016, why */-1);
toParse.append("-").append(calendar.get(Calendar.MONTH) + 1 < 10 ? "0" : "")
.append(calendar.get(Calendar.MONTH)+1);
toParse.append("-").append(calendar.get(Calendar.DAY_OF_MONTH) < 10 ? "0" : "")
.append(calendar.get(Calendar.DAY_OF_MONTH));
toParse.append(" ").append(calendar.get(Calendar.HOUR_OF_DAY) < 10 ? "0" : "")
.append(calendar.get(Calendar.HOUR_OF_DAY));
toParse.append(":").append(calendar.get(Calendar.MINUTE) < 10 ? "0" : "")
.append(calendar.get(Calendar.MINUTE));
toParse.append(":").append(calendar.get(Calendar.SECOND) < 10 ? "0" : "")
.append(calendar.get(Calendar.SECOND));
localDateTime = LocalDateTime.parse(toParse, FORMATTER);
//Why 2015 and not 2016?
assertEquals("2015-01-01T23:59:59", localDateTime.toString());
}
it bugs me with is 2015 and not 2016, be aware that the solution is hammered to give you 2015 instead of 2016.
I'm still using Joda and no java8, but there it would be
Chronology lenient = LenientChronology.getInstance(ISOChronology.getInstance());
DateTimeFormatter FORMATTER = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:sssss").withChronology(lenient);
DateTime dateTime = DateTime.parse("2016-01-01 00:00:86399", FORMATTER);
assertEquals("2016-01-01T23:59:59", dateTime.toLocalDateTime().toString());
Maybe you can obtain the same behavior using:
DateTimeFormatter formatter =
DateTimeFormatter.ISO_LOCAL_DATE.withResolverStyle(ResolverStyle.LENIENT);