How easy is it to analyze a date without a specified year?

I have a tool that seems to give me dates without specifying the year I need to convert, and I use Java for the task (actually Groovy, but close enough in this case). The approximate date is December 13, 12:00:00, which should be indicated on 12/13/2011, since the year is unspecified, and this is 2011. The following Groovy script does the trick:

import java.text.* println new SimpleDateFormat("dd MMM HH:mm:ss").parse("13 Dec 12:00:00") 

My problem with this script is that SimpleDateFormat seems to be leaving the year after 1970. I could directly set it to 2011, because this is the current year, but there seems to be some lag between the current year and the dates set so that when new years come, this script will be erroneous during this delay time. How can I fix it simply? One solution would be to check if the date with the current year after that will use the last year, but I hope that there is a simpler solution (or indicate that the simplest if not).

+5
source share
5 answers

You can use java.util.Calendar to get the current year, as in the example below.

 Calendar.getInstance ().get (Calendar.YEAR); 

Fragment Example

The OP developed its own question, and therefore this fragment was rewritten in accordance with its needs.

  public static String fixDate (String data) throws Exception { SimpleDateFormat dateInputFormat = new SimpleDateFormat("dd MMM HH:mm:ss"); SimpleDateFormat dateOutputFormat = new SimpleDateFormat("yyyy dd MMM HH:mm:ss"); Calendar currentCal = Calendar.getInstance (); Calendar parsedCal = Calendar.getInstance (); int CAL_YEAR = Calendar.YEAR; parsedCal.setTime (dateInputFormat.parse (data)); parsedCal.set (CAL_YEAR, currentCal.get (CAL_YEAR)); if (parsedCal.after (currentCal)) parsedCal.set (CAL_YEAR, parsedCal.get (CAL_YEAR) - 1); // Date parsedDate = parsedCal.getTime (); return dateOutputFormat.format (parsedCal.getTime ()); } public static void main (String[] args) throws Exception { System.out.println (fixDate ("13 Dec 12:00:00")); System.out.println (fixDate ("31 Dec 12:00:00")); } 

Output

2011 Dec 13 12:00:00

2010 Dec 31 12:00:00


Do not forget to leave the throw Exceptions !

+5
source

The modern answer (valid from 2014 onwards): first I declare a helper method:

 private static LocalDateTime parseWithDefaultYear(String stringWithoutYear, int defaultYear) { DateTimeFormatter parseFormatter = new DateTimeFormatterBuilder() .appendPattern("dd MMM HH:mm:ss") .parseDefaulting(ChronoField.YEAR, defaultYear) .toFormatter(Locale.ENGLISH); LocalDateTime dateTime = LocalDateTime.parse(stringWithoutYear, parseFormatter); return dateTime; } 

Then we can do:

  ZoneId zone = ZoneId.of("America/Argentina/Jujuy"); String stringWithoutYear = "13 Dec 12:00:00"; LocalDateTime now = LocalDateTime.now(zone); int defaultYear = now.getYear(); LocalDateTime dateTime = parseWithDefaultYear(stringWithoutYear, defaultYear); if (dateTime.isAfter(now)) { // in the future defaultYear--; dateTime = parseWithDefaultYear(stringWithoutYear, defaultYear); } System.out.println(dateTime); 

When launched today (June 2018), this prints:

2017-12-13T12: 00

You may ask why I want to parse a second time with the new formatter if the first attempt gives a date in the future. Isn’t it easier to subtract 1 year? Although java.time certainly has good support for this, I chose the second parsing to better deal with the corner case on February 29 in leap years. Imagine that the code runs in the first couple of months of 2021, and the line is 29 Feb 12:00:00 . Since 2021 is not a leap year, Java will choose February 28, the last day of the month. Subtracting 1 year will give February 28, 2020, which would be wrong, since 2020 is a leap year. Instead, my new 2020 analysis by default gives the correct value on February 29, 2020.

Messages:

  • Although the other answers were good in 2011, the Date , SimpleDateFormat , Calendar and GregorianCalendar classes are long outdated, so I recommend avoiding them. Modern classes tend to be more programmer friendly and bring fewer unpleasant surprises.
  • Always indicate the correct time zone. Using the wrong time zone may cause the test for future date-time to be inaccurate, which may lead to the result being rejected for 1 year.
  • Always indicate explicit language. In this case, I took "Dec" for the English language and provided Locale.ENGLISH .
  • Since you consider it safe to assume that this date refers to the last year, I invite you to think about whether, for example, can it also be assumed that this date has occurred in the last 4, 6 or 8 months? If so, checking if this is the case will give you a better check:

     if (dateTime.isBefore(now.minusMonths(5))) { throw new IllegalArgumentException("Not within the last 5 months: " + stringWithoutYear); } 
+5
source
  String date_string = "13 Dec 12:00:00"; SimpleDateFormat sdf = new SimpleDateFormat("dd MMM HH:mm:ss yyyy"); Date date = sdf.parse(date_string + " " + Calendar.getInstance ().get(Calendar.YEAR)); System.out.println(date); 

OUTPUT:

 Tue Dec 13 12:00:00 IST 2011 
+1
source

The simplest solution is to add the current year to the date string before analyzing it. For instance:

 def currentYear = new Date()[Calendar.YEAR] def d = Date.parse("dd MMM HH:mm:ss yyyy", "13 Dec 12:00:00 " + currentYear) println d ===> Tue Dec 13 12:00:00 MST 2011 
0
source
  GregorianCalendar now = new GregorianCalendar(); GregorianCalendar goal= new GregorianCalendar(now.get(Calendar.YEAR), month-1, day); if (goal.after(now)) { goal.add(Calendar.YEAR, -1); } 

target has a fixed date.

0
source

Source: https://habr.com/ru/post/1386563/


All Articles