I am using the SimpleDateFormatter
public static final DateFormat DATE_FORMAT_FULL_FULL_SPACES =
new SimpleDateFormat("dd MMMM yyyy", Locale.getDefault());
and Current Date is passed at that time, It should display as
1st JULY 2014 where st should be superscript.
How can I go further ?
Create these methods
private String getFormatedDate(){
String dayNumberSuffix = getDayNumberSuffix(Calendar.getInstance().get(Calendar.DAY_OF_MONTH));
SimpleDateFormat dateFormat = new SimpleDateFormat(" d'" + dayNumberSuffix + "' MMMM yyyy");
return dateFormat.format(Calendar.getInstance().getTime());
}
private String getDayNumberSuffix(int day) {
if (day >= 11 && day <= 13) {
return "<sup>th</sup>";
}
switch (day % 10) {
case 1:
return "<sup>st</sup>";
case 2:
return "<sup>nd</sup>";
case 3:
return "<sup>rd</sup>";
default:
return "<sup>th</sup>";
}
}
How to call?
String str = getFormatedDate();
txtDate.setText(Html.fromHtml(str));
OutPut :
The superscript part isn't the first tricky part here - although it's not clear how you'd want that to be represented anyway (HTML with <sup> tags? something else?)
The first tricky part is knowing how to get the ordinal (st, nd, rd, th) and doing that appropriately for different cultures (which can have very different rules). This isn't something that SimpleDateFormat supports, as far as I'm aware. You should also be aware that different cultures might not use dd MMMM yyyy as their normal full date format - it could look very odd to some people.
I would think very carefully about:
Which locales you need to support
Whether you really need the ordinal part
How you want the superscript to be represented in a string
If you only need to handle English, then the ordinal part isn't too hard (you can probably find examples of a String getOrdinal(int value) method online, or write your own in 5 minutes). If you're also happy to always use a "day first" format, then you'd probably only need to format the month and year in SimpleDateFormat, e.g.
public String formatWithOrdinal(Calendar calendar) {
DateFormat formatter = new SimpleDateFormat(" MMMM yyyy", Locale.getDefault());
formatter.setTimeZone(calendar.getTimeZone());
int day = calendar.get(Calendar.DATE);
return day + toSuperscript(getOrdinal(day)) + formatter.format(calendar.getTime());
}
Where toSuperscript would use HTML or whatever you need to superscript the value.
In short, you have a lot of separable concerns here - I strongly suggest you separate them, work out your exact requirements, and then implement them as simply as you can.
Related
I have code in Java for Selenium Webdriver TestNG. Is for comparing if the date on the website is same as today date.
Problem is that date on webpage dateOnWebpage for 11th April 2018 is in format
Today 4/11/2018
So I made selecter to compare date formats if months < 10 if(javaDateSelector < 10) than date to compare is in format M/dd/yyyy else is in format MM/dd/yyyy.
Is there better way to code it than I made it? Because I needed to parse date to string and than to int to compare it and code is quite long.
#Test(priority=3)
public void test3DateCheck() throws Exception
{
String dateOnWebpage = driver.findElement(By.xpath("//div[#id='homeCalendarSection']/div/div[2]/table/tbody/tr/td/div/ul/li")).getText();
System.out.println("Today Date on webpage is : " + dateOnWebpage);
//DateFormat dateFormat1 = new SimpleDateFormat("M/dd/yyyy");
DateFormat dateFormat1 = new SimpleDateFormat("MM");
Date date = new Date();
String javaDate1 = dateFormat1.format(date);
int javaDateSelector = Integer.parseInt(javaDate1);
if(javaDateSelector < 10)
{
DateFormat dateFormat2 = new SimpleDateFormat("M/dd/yyyy");
String javaDate2 = dateFormat2.format(date);
System.out.println("Today Date from Java is : " + javaDate2);
Assert.assertEquals(dateOnWebpage, "Today " + javaDate2);
}
else
{
DateFormat dateFormat3 = new SimpleDateFormat("MM/dd/yyyy");
String javaDate3 = dateFormat3.format(date);
System.out.println("Today Date from Java is : " + javaDate3);
Assert.assertEquals(dateOnWebpage, "Today " + javaDate3);
}
}
If you don’t care whether the date on the web page is written with leading zero for month and day of month or not and just want to test whether the date is correct:
DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("'Today' M/d/uuuu");
LocalDate today = LocalDate.now(ZoneId.of("Pacific/Norfolk"));
System.out.println("Today is " + today);
LocalDate observedDate = LocalDate.parse(dateOnWebpage, dateFormatter);
Assert.assertEquals(today, observedDate);
Rather than testing the string I am parsing the date and testing it. Even though the pattern has one M and one d in it, parsing two-digit months and two-digits day of month poses no problem.
If on the other hand you also want to test that the date on the web page is written without any leading zeroes, it’s best to test the string, like you already did:
DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("M/d/uuuu");
LocalDate today = LocalDate.now(ZoneId.of("Pacific/Norfolk"));
String todayString = today.format(dateFormatter);
System.out.println("Today is " + todayString);
Assert.assertEquals("Today " + todayString, dateOnWebpage);
Again, even though the pattern has one M and one d in it, two digits will be printed if the month or the day of month is greater than 9. What else could the format method do? If you require two-digit day of month always, put dd in the format pattern string.
In both snippets please fill in your desired time zone where I put Pacific/Norfolk since it is never the same date everywhere on the globe.
I am using and recommending java.time, the modern Java date and time API. DateFormat and SimpleDateFormat are not only long outdated, they are also notoriously troublesome. Date is just as outdated. I would avoid those classes completely. The modern API is generally so much nicer to work with.
Link: Oracle tutorial: Date Time explaining how to use java.time.
I'm trying to use Java 8 to re-format today's date but I'm getting the following error:
java.time.format.DateTimeParseException: Text '09-OCT-2017' could not be parsed:
Unable to obtain LocalDate from TemporalAccessor:
{WeekBasedYear[WeekFields[SUNDAY,1]]=2017, MonthOfYear=10, DayOfYear=9},ISO of type java.time.format.Parsed
Code:
public static String formatDate(String inputDate, String inputDateFormat, String returnDateFormat){
try {
DateTimeFormatter inputFormatter = new DateTimeFormatterBuilder().parseCaseInsensitive().appendPattern(inputDateFormat).toFormatter(Locale.ENGLISH);
LocalDate localDate = LocalDate.parse(inputDate, inputFormatter);
DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern(returnDateFormat);
String formattedString = localDate.format(outputFormatter);
return formattedString;
} catch (DateTimeParseException dtpe) {
log.error("A DateTimeParseException exception occured parsing the inputDate : " + inputDate + " and converting it to a " + returnDateFormat + " format. Exception is : " + dtpe);
}
return null;
}
I previously tried using SimpleDateFormat, but the problem is my inputDateFormat format is always in uppercase DD-MMM-YYYY, which was giving me incorrect results, so I tried using parseCaseInsensitive() to ignore the case sensitivity.
In the comments you told that the input format is DD-MMM-YYYY. According to javadoc, uppercase DD is the day of year field, and YYYY is the week based year field (which might be different from the year field).
You need to change them to lowercase dd (day of month) and yyyy (year of era). The parseCaseInsensitive() only takes care of the text fields - in this case, the month name (numbers are not affected by the case sensitivity - just because the month is in uppercase, it doesn't mean that the numbers patterns should also be).
The rest of the code is correct. Example (changing the format to yyyyMMdd):
String inputDate = "09-OCT-2017";
DateTimeFormatter inputFormatter = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
// use "dd" for day of month and "yyyy" for year
.appendPattern("dd-MMM-yyyy")
.toFormatter(Locale.ENGLISH);
LocalDate localDate = LocalDate.parse(inputDate, inputFormatter);
// use "dd" for day of month and "yyyy" for year
DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("yyyyMMdd");
String formattedString = localDate.format(outputFormatter);
System.out.println(formattedString); // 20171009
The output of the code above is:
20171009
Regarding your other comment about not having control over the input pattern, one alternative is to manually replace the letters to their lowercase version:
String pattern = "DD-MMM-YYYY";
DateTimeFormatter inputFormatter = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
// replace DD and YYYY with the lowercase versions
.appendPattern(pattern.replace("DD", "dd").replaceAll("YYYY", "yyyy"))
.toFormatter(Locale.ENGLISH);
// do the same for output format if needed
I don't think it needs a complex-replace-everything-in-one-step regex. Just calling the replace method multiple times can do the trick (unless you have really complex patterns that would require lots of different and complex calls to replace, but with only the cases you provided, that'll be enough).
I hope I got you right.
Formatting a String to LocalDate is acutally pretty simple. Your date format is that here right 09-Oct-2017?
Now you just need use the split command to divide that into a day, month and year:
String[] tempStr = inputDate.split("-");
int year = Integer.parseInt(tempStr[2]);
int month = Integer.parseInt(tempStr[1]);
int day = Integer.parseInt(tempStr[0]);
After that it´s pretty easy to get that to LocalDate:
LocalDate ld = LocalDate.of(year, month, day);
I hope that helps.
This question already has answers here:
How to parse case-insensitive strings with JSR-310 DateTimeFormatter?
(3 answers)
Closed 6 years ago.
Been trying for 4 hours to figure this out.
:This works
String date = "Jul-01-2014 09:10:12";
LocalDateTime dt = LocalDateTime.parse(date, DateTimeFormatter.ofPattern("MMM-dd-yyyy HH:mm:ss", Locale.US));
:This will not
String date = "JUL-01-2014 09:10:12";
LocalDateTime dt = LocalDateTime.parse(date, DateTimeFormatter.ofPattern("MMM-dd-yyyy HH:mm:ss", Locale.US));
Only difference being the month all capitalized. Proper case of Jul works. Neither JUL or jul will work. I also tried pattern of 'LLL' with no luck. What am I missing??
Well apparently I needed to spend 5 hours on this.
While writing an extension to provide a workaround I discovered this.
String date = "01-JUL-2014 09:10:12";
DateTimeFormatterBuilder fmb = new DateTimeFormatterBuilder();
fmb.parseCaseInsensitive();
fmb.append(DateTimeFormatter.ofPattern("dd-MMM-yyyy HH:mm:ss"));
LocalDateTime dt = LocalDateTime.parse(date, fmb.toFormatter());
Works great for all case styles.
It doesn't look like that is supported by the official API.
Symbol Meaning Presentation Examples
------ ------- ------------ -------
G era text AD; Anno Domini; A
u year year 2004; 04
y year-of-era year 2004; 04
D day-of-year number 189
M/L month-of-year number/text 7; 07; Jul; July; J
d day-of-month number 10
The only option for month-of-year is there, and it does not explicitly mention any format supporting three capital letter months.
It's not terribly difficult to convert it back into a format that Java can respect though; it involves a wee bit of finagling the date and putting it back into a single String, though.
The solution below isn't as elegant or as clean as using a third party, but the added benefit is that one doesn't have to rely on the third party library for this code at all.
public String transformToNormalizedDateFormat(final String input) {
String[] components = input.split("-");
String month = components[0];
if(month.length() > 3) {
throw new IllegalArgumentException("Was not a date in \"MMM\" format: " + month);
}
// Only capitalize the first letter.
final StringBuilder builder = new StringBuilder();
builder.append(month.substring(0, 1).toUpperCase())
.append(month.substring(1).toLowerCase())
.append("-");
final StringJoiner stringJoiner = new StringJoiner("-");
Arrays.stream(components, 1, components.length).forEach(stringJoiner::add);
builder.append(stringJoiner.toString());
return builder.toString();
}
Try using DateTimeFormatterBuilder and making parser case-insensitive. Don't forget to specify locale. Otherwise month abbreviation might not be parsed by MMM in default locale:
DateTimeFormatter format = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.appendPattern("dd-MMM-yyyy")
.toFormatter(Locale.ENGLISH);
LocalDate.parse("03-jun-2015", format);
M by definition takes July; Jul; 07. You might want to try (solution being a little ugly):
date = Character.toUpperCase(date.charAt(0)) + date.substring(1).toLowerCase();
LocalDateTime dt = LocalDateTime.parse(date, DateTimeFormatter.ofPattern("MMM-dd-yyyy HH:mm:ss", Locale.US));
Or you can try using WordUtils from apache-commons for capitalize.
I have a date as APR-JUN10 or APR-JUN 2010 and i need output as 2010-06-30 I need the best way to parse above date in java and should be flexible in adding more such format of dates. note: APR-JUN10 will not parse by any java api, we have to break down APR & JUN 10 and get date as 2010-06-30.
You need to firm up your requirements.
Currently all you have told us is that APR-JUN 2010 should translate to the last day of June.
But what about FEB-JUN 2010? Should that also translate to the last day of June? Or should it throw a parse exception due to not being a full quarter? What about JUL-JUN 2010, where the second month is before the first? What about MAY-JUL 2010 -- three months but perhaps your definition of "quarter" requires starts of January, April, July, October.
Once you have your own requirements down, you can get to work on the conversion.
It's unlikely that an existing DateFormat implementation will do this exact task for you. You're likely to need to parse the string in your own code.
If the only legal options are JAN-MAR, APR-JUN, JUL-SEP, OCT-DEC, then you just have a five-way switch statement to set the month and day on a Calendar object (the fifth way being a default: case that throws an exception.
If your requirement is more complex, then your code will need to be more complex. Breaking the string into parts using a regex would be a good first step.
Pattern patt = Pattern.compile("(.{3})-(.{3}) (\d+)");
Matcher matcher = patt.matcher(qaurterString);
if(! matcher.find() || m.groupCount() != 3) {
throw new ParseException(...)
}
String fromMonth = matcher.group(1);
String toMonth = matcher.group(2);
int year = Integer.parseInt(matcher.group(3));
I think you'll have to write parsing code from scratch, whatever you do. The neatest end result would for you to create a class that implements DateFormat.
String s = "APR-JUN10";
// validation of quarter part
String quarter = s.substring(0, 7);
if (
!quarter.equals("JAN-MAR") && !quarter.equals("APR-JUN")
&& !quarter.equals("JUL-SEP") && !quarter.equals("OCT-DEC")
) {
throw new IllegalArgumentException("Input is not a quarter date: " + s);
}
// text processing with preprocessing hack (substring(4))
SimpleDateFormat inputFormat = new SimpleDateFormat("MMMyy", Locale.ENGLISH);
inputFormat.setLenient(false);
Date date = inputFormat.parse(s.substring(4));
System.out.println(date);
// Output: Tue Jun 01 00:00:00 CEST 2010 [format chooses 1 as default day-of-month]
// Go to end of month/quarter
GregorianCalendar gcal = new GregorianCalendar();
gcal.clear();
gcal.setTime(date);
gcal.set(Calendar.DAY_OF_MONTH, gcal.getActualMaximum(Calendar.DAY_OF_MONTH));
// format as ISO-date
SimpleDateFormat outputFormat = new SimpleDateFormat("yyyy-MM-dd");
String output = outputFormat.format(gcal.getTime());
System.out.println(output); // 2010-06-30
For the input "APR-JUN 2010" you need the input format pattern "MMM yyyy", else the solution is the same. Of course, the proposed solution assumes that every input starts with JAN-MAR, APR-JUN, JUL-SEP or OCT-DEC (you wrote about quarters). If you want you can validate it before processing phase by mean of s.substring(0, 7) etc.
UPDATE: I have now added the validation feature, see code.
I need to get the number of minutes between two dates. I know Joda is the best to use, but this is for an Android project, so I prefer to use a little external libraries as possible, and the app I'm building doesn't require the calculation to be surgically precise.
However, the code I'm using doesn't seem to be working. I'm trying to get the number of minutes between "11/21/2011 7:00:00 AM" and "11/21/2011 1:00:00 PM" (which should be 360 minutes), but the code I'm using returns 0:
int diff = minutesDiff(GetItemDate("11/21/2011 7:00:00 AM"), GetItemDate("11/21/2011 1:00:00 PM"));
public static Date GetItemDate(final String date)
{
final Calendar cal = Calendar.getInstance(TimeZone.getDefault());
final SimpleDateFormat format = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss a");
format.setCalendar(cal);
try {
return format.parse(date);
} catch (ParseException e) {
return null;
}
}
public static int minutesDiff(Date earlierDate, Date laterDate)
{
if( earlierDate == null || laterDate == null ) return 0;
return (int)((laterDate.getTime()/60000) - (earlierDate.getTime()/60000));
}
If your GetItemDate is failing for either date, you will get zero. On the catch statement, place a println or debug to output the issue and see if that tells you something.
Also, just as a matter of practice, I'd change:
return (int)((laterDate.getTime()/60000) - (earlierDate.getTime()/60000));
to:
long result = ((laterDate.getTime()/60000) - (earlierDate.getTime()/60000));
return (int) result;
This gives you the opportunity to view the result of the math in an IDE.
I debugged through your code: there is ParseException in GetItemDate() for both of the date strings like:
Unparseable date: 11/21/2011 07:00:00 AM
The problem is that parsing AM/PM hours only works with "hh" (small caps!) or "KK". At least that is the case in my phone (it seems some of us didn't see this issue at all). I tested it also works with a single "h" too.
hh = 1-12
KK = 0-11
HH = 0-23
kk = 1-24
Change your SimpleDateFormat line to this:
final SimpleDateFormat format = new SimpleDateFormat("MM/dd/yyyy hh:mm:ss a", Locale.US);
This post explains the "a" and Locale: Unable to parse DateTime-string with AM/PM marker
PS. I'm from Finland so I must use the "Locale.US" part for this to work. US residents may test the code without it, I think.