I am trying to parse string ISO dates (like "2016-01-01") to be able to format them.
#dates and #temporals seem to be only able to format Date/LocalDate/LocalDateTime objects.
For instance I want Thymeleaf to display "January 1st, 2016" when it is passed "2016-01-01".
Thanks.
Take a look the section Reformatting dates in our home page of the reference documentation.
....
...we can do just this:
WebContext ctx =
new WebContext(request, response, servletContext, request.getLocale()); ctx.setVariable("today",
Calendar.getInstance());
templateEngine.process("home", ctx, response.getWriter());
…and then perform date formatting in the view layer itself:
<p> Today is: <span th:text="${#calendars.format(today,'dd MMMM yyyy')}">13 May 2011</span> </p>
I ended up implementing my own dialect containing utility functions such as parseISODate(String date) which returns a LocalDate then in the HTML I can do
th:text="${#temporals.format(#myDialect.parseISODate(someStringISODate), 'dd/MMM/yyyy')}"
Related
Sorry to bother but I've been headbanging on this topic for 8 hours
tried all the suggested solutions here and there and nothing changes (in good).
If someone could help... pleaaaase ...
I have a view supposed to display a datepicker without the hours
#Html.EditorFor(model => model.OrderDateFilter, new { #class = "form-control datepicker" , #value = "'" + Model.OrderDateFilter.ToString("dd/MM/yyyy") + "'"})
and the display is always THIS
error display
HTML result
<input class="text-box single-line" data-val="true" data-val-date="The field OrderDateFilter must be a date." data-val-required="Le champ OrderDateFilter est requis." id="OrderDateFilter" name="OrderDateFilter" type="date" value="09/02/2023">
So whatever the value it is never displayed except when I click the datepicker and choose a new date, I post the form to the controler, value is kept, processed and is correctly set back to 'value' but never shown
I've tried to TextBoxFor options with #type='date', etc...
Tryed use boostrap datepicker but it's obviously ugly and I could never get rid of the hour 00:00:00 format always displayed by default
Here's the Model part for this date filter (if I don't add the 2 first Annotations it's the same)
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}", ApplyFormatInEditMode = true)]
public DateTime OrderDateFilter { get; set; } //---
18/03/2022 - EDIT
the date format in model etc.. MUST BE yyyy-MM-dd (because I don't need hours/minutes..) and no other format is possible. The datepicker displayed by Razor will pick the browser default culture to display the user's local format and will transate to yyyy-MM-dd in the controler etc..
then it works without jQuery datepicker or others
I've been trying to parse a simple date using JodaTime since yesterday and so far I keep on failing.....
Here's a (random) date I'm trying to parse:
2017-Sept-14 (Even with S in upper case doesn't change anything...)
Here's my code
DateTimeFormatter dateTimeFormat = DateTimeFormat.forPattern("yyyy-MM-dd");
// The variable 'parsed' is a dynamic string. For now I set it to 2017-sept-14
DateTime dateTime = dateTimeFormat.parseDateTime(parsed);
Log.d(TAG, "Parsed date = "+ dateTime.toString());
And here's the exception I have:
java.lang.IllegalArgumentException: Invalid format: "2017-sept-14" is malformed at "sept-14" at org.joda.time.format.DateTimeFormatter.parseDateTime(DateTimeFormatter.java:945)
What am I missing here ??
UPDATE:
Actually what I get from my textfield is in the form above i.e date-month-day (the month is 3 or 4 characters long depending on the month....)
So what I want to get as output when I have 2017-sept-14 is simply 2017-09-14
Joda-Time accepts the month name in a short format (in most languages, it's usually with 3 letters) or long format (with the full name). Your input seems to be in English and with 4 letters, which is not supported.
If it's possible to manipulate the input, you can remove the extra characters and make sure the month name contains just 3 letters.
I also use a java.util.Locale to specify that the month name is in English. If you don't specify a locale, it uses the system default, and it's not guaranteed to always be English, so it's better to specify one.
I also parse it to a LocalDate, because its toString() method already produces the output you want:
String input = "2017-Sept-14";
input = input.replace("Sept", "Sep");
DateTimeFormatter dateTimeFormat = DateTimeFormat.forPattern("yyyy-MMM-dd").withLocale(Locale.ENGLISH);
LocalDate dateTime = dateTimeFormat.parseLocalDate(input);
System.out.println(dateTime);
The output is:
2017-09-14
I was assuming that the locale was English, but in Estonia locale the short month name for September is "sept", so you could also do:
String input = "2017-Sept-14";
input = input.toLowerCase(); // et_EE locale accepts only "sept"
DateTimeFormatter dateTimeFormat = DateTimeFormat.forPattern("yyyy-MMM-dd")
.withLocale(new Locale("et", "EE"));
LocalDate dateTime = dateTimeFormat.parseLocalDate(input);
System.out.println(dateTime);
Or you can try with your system's default (based on your comments that SimpleDateFormat works with French locale, so there's a chance of the code above to also work).
Java new Date/Time API
Joda-Time is in maintainance mode and is being replaced by the new APIs, so I don't recommend start a new project with it. Even in joda's website it says: "Note that Joda-Time is considered to be a largely “finished” project. No major enhancements are planned. If using Java SE 8, please migrate to java.time (JSR-310).".
If you can't (or don't want to) migrate from Joda-Time to the new API, you can ignore this section.
In Android you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes. To make it work, you'll also need the ThreeTenABP (more on how to use it here).
You can create a formatter, set the locale and parse it to a LocalDate:
import org.threeten.bp.LocalDate;
import org.threeten.bp.format.DateTimeFormatter;
import org.threeten.bp.format.DateTimeFormatterBuilder;
DateTimeFormatter f = new DateTimeFormatterBuilder()
// case insensitive (so it accepts Sept, sept, and so on)
.parseCaseInsensitive()
// pattern
.appendPattern("yyyy-MMM-dd")
// set locale
.toFormatter(new Locale("et", "EE"));
System.out.println(LocalDate.parse("2017-Sept-14", f));
The output is:
2017-09-14
Or just try with your system's default locale (just call toFormatter() without arguments and it'll use the system default).
Optionally, you can create a map of custom month names and use it in the formatter. The only detail is that you have to fill it with values for all months. I put Sept in September, and you can fill the other months accordingly:
// map of custom names for month
Map<Long, String> monthNames = new HashMap<>();
// put the names used in your input
monthNames.put(1L, "Jan");
monthNames.put(2L, "Feb");
monthNames.put(3L, "Mar");
monthNames.put(4L, "Apr");
monthNames.put(5L, "May");
monthNames.put(6L, "Jun");
monthNames.put(7L, "Jul");
monthNames.put(8L, "Aug");
monthNames.put(9L, "Sept");
monthNames.put(10L, "Oct");
monthNames.put(11L, "Nov");
monthNames.put(12L, "Dec");
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
// case insensitive (so it accepts Sept, sept, and so on)
.parseCaseInsensitive()
// year
.appendPattern("yyyy-")
// month, using custom names
.appendText(ChronoField.MONTH_OF_YEAR, monthNames)
// day
.appendPattern("-dd")
// create formatter
.toFormatter();
String input = "2017-Sept-14";
System.out.println(LocalDate.parse(input, fmt));
Joda-Time does not offer a simple way. The only (complex) way would be to define your own implementation of DateTimeParser. You might find some inspiration how to implement it in another old SO-post from me and then do:
DateTimeParser monthParser = ...; // left as exercise to you
DateTimeFormatter joda =
new DateTimeFormatterBuilder()
.appendPattern("yyyy-")
.append(monthParser)
.append("-dd")
.toFormatter();
LocalDate ld = joda.parseLocalDate("2017-sept-14");
I am not sure why the answer of Hugo suggesting a map-based lookup of customized names does not work for you. Maybe the month names are variable and not fixed (for the same month). Maybe you just want to check if the month names start with the same prefix. If so then my lib Time4J might help you because it manages much more formatting/parsing attributes to control parsing, see following short example (it also manages additional trailing dots if present):
String s = "2017-sept.-14";
ChronoFormatter<PlainDate> f =
ChronoFormatter
.setUp(PlainDate.class, new java.util.Locale("fr", "FR"))
.addPattern("uuuu-MMM", PatternType.CLDR)
.skipUnknown(c -> c == '.', 1)
.addPattern("-dd", PatternType.CLDR)
.build()
.with(net.time4j.format.Attributes.PARSE_CASE_INSENSITIVE, true)
.with(net.time4j.format.Attributes.PARSE_PARTIAL_COMPARE, true);
System.out.println(f.parse(s)); // 2017-09-14
For Android, you would replace Time4J by Time4A and also replace the given lambda-expression by an anonymous class implementing the ChronoCondition-interface.
By the way, a lookup-table for fixed month names is possible with every library. For Joda, see my older SO-post mentioned above as link. For Java-8 or the threeten-backport see the answer of Hugo. For SimpleDateFormat see how to set a suitable instance of DateFormatSymbols. For Time4J, see the builder-API (similar to Java-8).
A final word about SimpleDateFormat. Even if it seems to work for you now (just because of lenient parsing which works for old Java and Time4J but interestingly not for java.time-API), I would still not trust it in every situation, and this old parser class is not thread-safe, too.
You need a two digits number for the month (09) if you want to keep the pattern yyyy-MM-dd. Otherwise change your pattern to yyyy-MMMM-dd.
So I don't know know if it's the right way but this worked for me (I ended up using SimpleDateFormat...) :
SimpleDateFormat sdfSource = new SimpleDateFormat("yyyy-MMM-dd");
SimpleDateFormat sdfDestination = new SimpleDateFormat("yyyy-MM-dd");
try {
Date date = sdfSource.parse(parsed);
String strOutput = sdfDestination.format(date);
Log.d(TAG, "Parsed date = "+ strOutput);
} catch (ParseException e) {
e.printStackTrace();
}
I have one property in my cq dialog whose xtype is datetime. Value is stored like this "2016-04-11T03:00:00.000-04:00" in cq and name of the property is eventDate.
I would like to know two things here -
How can i read the date and time from this property in sightly html.
When i passing this date as the parameter in my Use class (Java class), this is getting passed as null. However, when i pass currentPage.lastModified, then i can see the date value.
Any pointers will be highly appreciated.
Not sure of the approach using sightly.
To provide an alternate solution -
You could probably used jcr api's on the node containing datetime property.
java.text.SimpleDateFormat api can be used to efficiently extract date and time.
For eg:
SimpleDateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy");
dateFormat.format(node.getProperty(eventDate).getValue().getDate().getTime())
Similarly to persist date in datetime you could probably use com.day.cq.commons.date.DateUtil api
node.setProperty(propertyName, DateUtil.parseISO8601(DateUtil.getISO8601Date(Calendar.getInstance())))
I guess the missing part is, you are not adding the use class inside your sightly. Your sightly should have this:
<div data-sly-use.eventUseObj = "com.test.models.EventModel" data-sly-unwrap />
The respective java use class should have overridden activate() method like this:
public class EventModel extends WCMUse {
private String eventDate;
#Override
public void activate() {
Calendar eventCalendar = getProperties().get("eventDate", Calendar.class);
DateFormat outputFormat = new SimpleDateFormat("yyyy-MM-dd");
eventDate = outputFormat.format(eventCalendar.getTime());
}
}
Now this date can be easily used back in sightly like this:
${eventUseObj.eventDate}
This will print the value of the date on page. There are ampty number of date patterns supported by SimpleDateFormat and you may choose the one required.
here's a simple example with javascript UseAPI, the logic should hold true with Java UseAPI
dateformater.js file :
"use strict";
//dateformatter.js
use(function () {
var formattedDate = new java.text.SimpleDateFormat(this.mask).format(this.date);
return {
formattedDate: formattedDate
};
});
and HTL (Sightly) markup example :
<h1 data-sly-use.formatter="${'dateformatter.js' # date=properties.eventDate.time, mask='dd/MM/yyyy hh:mm:ss'}">
Event date formatted: ${formatter.formattedDate}
</h1>
Sightly has built-ins that support formatting string, date and numbers. Here is how you can format date in a specific format.
${'yyyy-MM-dd HH:mm:ss.SSSXXX' # format=obj.date, timezone='UTC'}
${'yyyy-MM-dd HH:mm:ss.SSSXXX' # format=obj.date, timezone='GMT+02:00'}
The timezone parameter is optional, so if you want the time in the default timezone then you can just omit the timezone parameter.
${'yyyy-MM-dd HH:mm:ss.SSSXXX' # format=obj.date}
You can read more about it here - https://github.com/adobe/htl-spec/blob/1.3/SPECIFICATION.md#1222-dates
When I try to use date format tag in gsp view to change the format of my date but it doesn't work.
This is my code:
class MyDate {
Date date
}
MyDateController:
....
def unixSeconds = params["date"].replaceAll("\"", "") as long //params["date"]="1386157660"
Date date = new Date(unixSeconds*1000L)
myDateInstance = new MyDate(date:date)
....
gsp View:
${myDateInstance.date.format('yyyy-MM-dd HH:mm')}
The format that I have is 2013-12-04 12:47:40.0 instead of 2013-12-04 12:47
Afaict, that shouldn't happen and I can't see how it is happening...
Are you sure that's the line of code that's generating the output you're seeing?
You could try the Grails formatDate tag in its place:
<g:formatDate format="yyyy-MM-dd HH:mm" date="${myDateInstance.date}"/>
You can use "formatDate" in value attribute like following
<g:textField name="saleDate" value="${formatDate(format:'dd-MM-yyyy',date:saleItem?.saleDate)}"/>
In addition to #tim_yates's answer above, there is another point I want to add:
I observed that if type and style are given, format is not used. I think they work as alternatives for each other. Also, using format would be beneficial as the Date string format could differ on different operating systems.
I have seen a few posts related to using the g:datePicker in Grails. Using this it looks like you can just pick the value off the params like so params.myDate.
However, when I try to do something like this in my view:
view:
<g:link controller="c" action="a" params="[fromDate:(new Date())]">
controller:
def dateval = params.fromDate as Date
The date is not parsing out correctly. Is there something else I should be doing in the view to make the date 'parsable' by the controller. I've looked around and haven't found this in any posts where datePicker is not used.
I prefer to send time instead of dates from the client.
<g:link controller="c" action="a" params="[fromDate:(new Date().time)]">
And in action I use the constructor of Date that takes time.
def date = params.date
date = date instanceof Date ? date : new Date(date as Long)
I have created a method in DateUtil class to handle this. This works fine for me.
When the parameters are sent to a controller they are sent as strings. The following won't work
def dateval = params.fromDate as Date
Because you haven't specified what date format to use to convert the string to a date. Replace the above with:
def dateval = Date.parse('yyyy/MM/dd', params.fromDate)
Obviously if your date is not sent in the format yyyy/MM/dd you'll need to change the second parameter. Alternatively, you can make this conversion happen automatically by registering a custom date editor
Whatever is sent from view is a string so params.fromDate as Date does not work.
In grails 2.x a date method is added to the params object to allow easy, null-safe parsing of dates, like
def dateval = params.date('fromDate', 'dd-MM-yyyy')
or you can pass a list of date formats as well, like
def dateval = params.date('fromDate', ['yyyy-MM-dd', 'yyyyMMdd', 'yyMMdd'])
or the format can be read from the messages.properties via key date.myDate.format and use date method of params as
def dateval = params.date('fromDate')