24

I need to generate a new Date object for credit card expiration date, I only have a month and a year, how can I generate a Date based on those two? I need the easiest way possible. I was reading some other answers on here, but they all seem too sophisticated.

antonpug
  • 13,724
  • 28
  • 88
  • 129
  • Why dont you use any digit between 1 and 31 for the day, for example 1? – krackmoe Sep 19 '12 at 16:38
  • No you have to use Calendar or GregorianCalendar. But you can set the day, month, year with: set(int year, int month, int date) and with getTime() you get a Date object returned – krackmoe Sep 19 '12 at 16:42
  • 1
    Why the hell does Java make this so much harder than it should be? – antonpug Sep 19 '12 at 16:45
  • 1
    Its not that difficult, its just a few lines of code – krackmoe Sep 19 '12 at 16:47
  • @krackmoe yeah...I mean it makes it harder to use it on the fly, as an argument, etc. I am REALLY surprised that you can't just have a simple declaration. – antonpug Sep 19 '12 at 16:48
  • @antonpug -- The [Date class](http://docs.oracle.com/javase/6/docs/api/java/util/Date.html) has some deprecated constructors that used to allow you to do stuff like `new Date("04/01/2013")` and `new Date(2013, 4, 1)`. In theory you could still use those, but it's not recommended. – Roddy of the Frozen Peas Sep 19 '12 at 16:52
  • Java makes it hard because its entire date, time, and calendar APIs are [broken](http://stackoverflow.com/questions/1969442/whats-wrong-with-java-date-time-api). The string to date constructor is deprecated, but if you _could_ use Joda-Time (sorry, can't resist!) then yes you could pass an ISO local date to the `LocalDate` constructor. – Ray Toal Sep 19 '12 at 16:55
  • Screw this. I decided I am using the deprecated constructor. There's absolutely no downside to doing that in my case. I am creating a single date value for testing purposes. – antonpug Sep 19 '12 at 16:56
  • I had similar problem and i used this solution http://stackoverflow.com/questions/21607728/sql-get-a-list-of-dates-in-month-year/21625989#21625989, hope it will help (if u are using mysql and java) – AdrianES Apr 29 '14 at 11:34

6 Answers6

44

You could use java.util.Calendar:

Calendar calendar = Calendar.getInstance();
calendar.clear();
calendar.set(Calendar.MONTH, month);
calendar.set(Calendar.YEAR, year);
Date date = calendar.getTime();
Reimeus
  • 158,255
  • 15
  • 216
  • 276
  • 2
    I can't use new Date("2013-05-01")? I haven't programmed in Java in a while, but from most languages, that would seem like a common sense way to do it? – antonpug Sep 19 '12 at 16:40
  • 6
    As a word of caution, the day field would be set to today's date. Check the intended behavior if the current day is outside of the bounds for the target month. For example, setting the month to February when `calendar` has a day field of 30. It might be wise to set the day to a known, valid value for every month (eg: 1) before setting the month and year. – Thomas Owens Sep 19 '12 at 16:41
  • You can replace `new GregorianCalendar()` with `Calendar.newInstance()` – Steve Kuo Sep 19 '12 at 17:10
  • Cannot see that method. Do you mean `Calendar.getInstance()`? – Reimeus Sep 19 '12 at 17:16
  • 6
    also, note that month is `0` based i.e. Jan is 0 not 1. – Vineet Menon Sep 22 '17 at 09:14
36

java.time

Using java.time framework built into Java 8

import java.time.YearMonth;

int year = 2015;
int month = 12;
YearMonth.of(year,month); // 2015-12

from String

YearMonth.parse("2015-12"); // 2015-12

with custom DateTimeFormatter

import java.time.format.DateTimeFormatter;

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM yyyy");
YearMonth.parse("12 2015", formatter); // 2015-12

Conversions To convert YearMonth to more standard date representation which is LocalDate.

LocalDate startMonth = date.atDay(1); //2015-12-01
LocalDate endMonth = date.atEndOfMonth(); //2015-12-31
Przemek
  • 7,111
  • 3
  • 43
  • 52
5

Possibly a non-answer since you asked for a java.util.Date, but it seems like a good opportunity to point out that most work with dates and times and calendars in Java should probably be done with the Joda-Time library, in which case

new LocalDate(year, month, 1)

comes to mind.

Joda-Time has a number of other nice things regarding days of the month. For example if you wanted to know the first day of the current month, you can write

LocalDate firstOfThisMonth = new LocalDate().withDayOfMonth(1);

In your comment you ask about passing a string to the java.util.Date constructor, for example:

new Date("2012-09-19")

This version of the constructor is deprecated, so don't use it. You should create a date formatter and call parse. This is good advice because you will probably have year and month as integer values, and will need to make a good string, properly padded and delimited and all that, which is incredibly hard to get right in all cases. For that reason use the date formatter which knows how to take care of all that stuff perfectly.

Other earlier answers showed how to do this.

Mohamed Taher Alrefaie
  • 15,698
  • 9
  • 48
  • 66
Ray Toal
  • 86,166
  • 18
  • 182
  • 232
4

Like

SimpleDateFormat formatter = new SimpleDateFormat("yyyy/MM");
Date utilDate = formatter.parse(year + "/" + month);

Copied from Create a java.util.Date Object from a Year, Month, Day Forma or maybe like

DateTime aDate = new DateTime(year, month, 1, 0, 0, 0);

Copied from What's the Right Way to Create a Date in Java?

Community
  • 1
  • 1
Anton Bessonov
  • 9,208
  • 3
  • 35
  • 38
0

The most common sense approach would be to use the Date("YYYY-MM-DD") constructor even though it is deprecated. This is the easiest way to create a date on the fly. Screw whoever decided to deprecate it. Long live Date("YYYY-MM-DD")!!!

antonpug
  • 13,724
  • 28
  • 88
  • 129
  • That constructor works unreliably across time zones. In short, it is not well defined what you get from it. You get that date at midnight in some time zone, that still leaves room for 26 or 27 hours of variation. The constructor was deprecated for a reason. – Ole V.V. Nov 25 '17 at 13:19
0

Don’t use this answer. Use the answers by Przemek and Ray Toel. As Przemek says, prefer to use a YearMonth for representing year and month. As both say, if you must use a date, use LocalDate, it’s a date without time of day.

If you absolutely indispensably need an old-fashioned java.util.Date object for a legacy API that you cannot change, here’s one easy way to get one. It may not work as desired, it may not give you exactly the date that you need, it depends on your exact requirements.

    YearMonth expiration = YearMonth.of(2021, 8); // or .of(2021, Month.AUGUST);
    Date oldFashionedDateObject = Date.from(expiration
            .atDay(1)
            .atStartOfDay(ZoneId.systemDefault())
            .toInstant());
    System.out.println(oldFashionedDateObject);

On my computer this prints

Sun Aug 01 00:00:00 CEST 2021

What we got is the first of the month at midnight in my local time zone — more precisely, my JVM’s time zone setting. This is one good guess at what your legacy API expects, but it is also dangerous. The JVM’s time zone setting may be changed under our feet by other parts of the program or by other programs running in the same JVM. In other words, we cannot really be sure what we get.

The time zone issue gets even worse if the date is transmitted to a computer running a different time zone, like from client to server or vice versa, or to a database running its own time zone. There’s about 50 % risk that your Date will come through as a time in the previous month.

If you know the time zone required in the end, it will help to specify for example ZoneId.of("America/New_York") instead of the system default in the above snippet.

If your API is lenient and just needs some point within the correct month, you’ll be better off giving it the 2nd of the month UTC or the 3rd of the month in your own time zone. Here’s how to do the former:

    Date oldFashionedDateObject = Date.from(expiration
            .atDay(2)
            .atStartOfDay(ZoneOffset.UTC)
            .toInstant());
Ole V.V.
  • 81,772
  • 15
  • 137
  • 161