So this sounds easy, just take the day and date in java and see if it's the same day using the system's time with the calendar. This I can do and this would be a question that's probably repeated multiple times on here.
But my question is how to get like Cyber Monday. Let's say I have a program and every year on Cyber Monday he needs to lower the prices in the shop by 70% or set the discount to 70%. (which is actually my goal) Should I use java calendar for it? Which I can I guess. But how should I do it? I can't just check for the day we are now is the same as 27-11-2017 because in 2018 it's not on 27-11-2018. So how should I calculate this or check for it?
Is it possible to use like a API which has annual events and where people can send a request to receive the date of the requested annual event? Like I noticed the google calendar API but this is only for calendars you made yourself. Which I'm not planning to add every annual event for my own.
I made this method, To check if it's CyberMonday, what it's main purpose is. At this moment I'm stuck doing it annually. How can I make this right for every year?
public static void CyberMonday() {
//Check here if it's Cybermonday or if it's day after cybermonday.
if(Server.getCalendar().getYMD().toString().equals("2017/11/27") ) {
Config.CYBER_MONDAY = true;
updateCyberMondayOnWebsite();
} else {
Config.CYBER_MONDAY = false;
}
}
You can use Java 8's new java.time API for that.
If you're using Java <= 7, you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes. And for Android, there's the ThreeTenABP (more on how to use it here).
The code below works for both.
The only difference is the package names (in Java 8 is java.time and in ThreeTen Backport (or Android's ThreeTenABP) is org.threeten.bp), but the classes and methods names are the same.
You can use LocalDate class to get Thanksgiving for a specified year (assuming that it's in US, so it's the fourth Thursday of November), and then get the next Monday after it.
I also use the TemporalAdjusters class, which has built-in methods to get those dates. The code is:
// get Cyber Monday of a specified year
public LocalDate getCyberMonday(int year) {
// Thanksgiving: fourth Thursday of November
// get first day of November
LocalDate d = LocalDate.of(year, 11, 1)
// get the fourth Thursday
.with(TemporalAdjusters.dayOfWeekInMonth(4, DayOfWeek.THURSDAY));
// next monday after Thanksgiving
return d.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
}
With this you can get the Cyber Monday for any year:
// get Cyber Monday for year 2017
LocalDate cyberMonday = getCyberMonday(2017);
So you can compare with another dates:
// checking if today is Cyber Monday
boolean isCyberMonday = cyberMonday.equals(LocalDate.now());
If the date you want to check is a String, you must parse it first (with a DateTimeFormatter) and then compare it.
I'm doing in a generic way: parsing the String, getting the year from it and comparing with the Cyber Monday of that year.
In this example, the date is in the same format of your example (2017/11/27):
String input = "2017/11/27";
// parse the input (in year/month/day format)
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy/MM/dd");
LocalDate parsedDate = LocalDate.parse(input, fmt);
// compare the parsed date with the Cyber Monday of the same year
LocalDate cyberMonday = getCyberMonday(parsedDate.getYear());
boolean isCyberMonday = cyberMonday.equals(parsedDate);
You must change the pattern to match your inputs. Check the DateTimeFormatter javadoc for more information about date patterns.
PS: LocalDate.now() will get the current date in the system's default timezone. If you want to guarantee it gets the current date in a specific timezone, you can do something like LocalDate.now(ZoneId.of("America/New_York")).
Note that I used America/New_York as the timezone: the API uses IANA timezones names (always in the format Region/City, like America/Sao_Paulo or Europe/Berlin).
Avoid using the 3-letter abbreviations (like CST or PST) because they are ambiguous and not standard.
You can get a list of available timezones (and choose the one that fits best your system) by calling ZoneId.getAvailableZoneIds().
Related
In our business requirement we are supposed to find out the first day of the week.
Since the client is European so I used following code to get it.
But, issue is when I run this code I am getting 2 as the answer where as I am expecting 1.
public class Test{
public static void main(String[] args) {
TimeZone eu = TimeZone.getTimeZone("Europe/Berlin");
Locale de = Locale.forLanguageTag("de");
int firstDayOfWeek = Calendar.getInstance(eu, de).getFirstDayOfWeek();
System.out.println(firstDayOfWeek);
}
}
Can some one help me understand this behavior.
Look at the docs:
Gets what the first day of the week is; e.g., SUNDAY in the U.S., MONDAY in France.
and here:
public static final int MONDAY 2
This shows that the return value depends on the locale.
If we print this:
System.out.println(firstDayOfWeek == Calendar.MONDAY);
We'll see true. This means that the first day of week is indeed Monday. It's just that you thought Monday is encoded by 1. In fact, Sunday is encoded as 1.
Locale de = Locale.forLanguageTag("de");
WeekFields wf = WeekFields.of(de);
DayOfWeek firstDayOfWeek = wf.getFirstDayOfWeek();
System.out.println(firstDayOfWeek);
This prints:
MONDAY
Don’t use the confusing old Calendar class. You got 2 as the first day of the week. But weren’t you supposed to get 1? Or 0? How are days of the week numbered? Forget about numbers, use the DayOfWeek enum from java.time, the modern Java date and time API.
For prettier output use DayOfWeek.getDisplayName or a DateTimeFormatter. If you do need a number, use DayOfWeek.getValue:
System.out.println(firstDayOfWeek.getDisplayName(TextStyle.FULL, de));
System.out.println(firstDayOfWeek.getValue());
Output is:
Montag
1
PS Also don’t use TimeZone and the other long outdated date and time classes. java.time is so much nicer to work with. This fact shows nicely in this example, but its typical, certainly no coincidence.
Link: Oracle tutorial: Date Time explaining how to use java.time.
According to the javadoc, MONDAY's valus is 2.
If I take current date from my application, it comes with variation like below:
scenario 1: when the date is less than 10th of the month, a month is less than 10 of the year --> example: 5/9/18
scenario 2: when the date is >= 10th of the month, a month is less >= 10 of the year --> example: 10/11/18
Note: all the examples are in MM/DD/YY format and timezone is the USA
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DATE,-2);
DateFormat dateFormat = new SimpleDateFormat("MM/dd/yy HH:mm a");
String PastDate = dateFormat.format(cal.getTime());
info("Date is displayed as : "+ PastDate );
The above piece of code throwing me an error when the scenario 1 is in place. But if I format the date-time as "M/d/yy H:mm a" it works for both the scenario. I need the date add also.
Will it be a good practice to use the 2nd format? or there is any other way to get it done. Expert guidance please..
java.time
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT)
.withLocale(Locale.US);
ZonedDateTime dayBeforeYesterday = ZonedDateTime.now(ZoneId.of("America/St_Thomas"))
.minusDays(2);
System.out.println(dayBeforeYesterday.format(formatter));
Running just now I got this output:
5/7/18, 8:44 AM
Please specify your desired time zone where I put America/St_Thomas. Think twice before you use ZoneId.systemDefault() for your JVM’s time zone setting since this setting may be changed at any time from other parts of your program or other programs running in the same JVM; but if you trust the setting reflects the user’s time zone, it’s the correct thing to use.
Rather than defining your own output format prefer using one of the built-in formats you get from DateTimeFormatter.ofLocalizedDateTime. Do specify locale (no matter if you use a built-in format or roll your own). Again, use Locale.getDefault() if you trust the JVM’s setting is correct.
Avoid the old date and time classes like Calendar, DateFormat and SimpleDateFormat. They are not only long outdated, they are also poorly designed and the last two in particular notoriously troublesome. Today we have so much better in java.time, the modern Java date and time API.
Link: Oracle tutorial: Date Time explaining how to use java.time.
The number of characters in the format MM indicates that two digits are required in the input. A single character M will match one or two digits. Use M/d/yy H:mm a to support your desired formats.
I have to write a program which shows a Timeplan about when to send emails.
The User is inputing a Start date and I have to show the timeplan for one year.
How do I loop the Task?
In this example the mails should be sent every 8 days.
if(recipient==0) {
System.out.println("send mail on this day:" +calendar.getTime());
calendar.add((GregorianCalendar.DAY_OF_YEAR),8);
return true;
}
I would like to loop the System.out.println and the calendar.add task until it is one year later.
edit: I have another case where it should send the emails every 16 days but when the day is a saturday or sunday it should send the mail on the following monday.
I did it like this but now I get more dates than I need.
if(empfaenger==1)
{
for (Date d=startDate; d.before(endDate); d.setTime(d.getTime() + (1000 * 60 * 60 * 24 * 8)))
{
if(calendar.get(calendar.DAY_OF_WEEK)==1)
{
calendar.add((GregorianCalendar.DAY_OF_YEAR),1);
System.out.println("mail will be sent on this day:"+calendar.getTime());
calendar.add((GregorianCalendar.DAY_OF_YEAR), 16);
}
else if(calendar.get(calendar.DAY_OF_WEEK)==7)
{
calendar.add((GregorianCalendar.DAY_OF_YEAR), 2);
System.out.println("mail will be sent on this day:"+calendar.getTime());
calendar.add((GregorianCalendar.DAY_OF_YEAR),16);
}
else
{
System.out.println("mail will be sent on this day:"+calendar.getTime());
calendar.add((GregorianCalendar.DAY_OF_YEAR),16);
}
//System.out.println(calendar.getTime;)
}
}
Here is a sample using java.time api from java 8 , it's much more easier to understand and use compered to calendar or date classes :
static void sendEveryEightDays(){
LocalDateTime timeToSendEmail= LocalDateTime.now();
LocalDateTime afterAYear = timeToSendEmail.plusYears(1);
while(timeToSendEmail.isBefore(afterAYear)){
System.out.println("SendTheEmail "+timeToSendEmail.toString());
timeToSendEmail=timeToSendEmail.plusDays(8);
}
}
if you want to take the user's time zone into consideration you can use ZonedDateTime instated off LocalDateTime :
static void sendEveryEightDays(ZoneId userTimeZone){
ZonedDateTime timeToSendEmail= ZonedDateTime.now(userTimeZone);
ZonedDateTime afterAYear = timeToSendEmail.plusYears(1);
while(timeToSendEmail.isBefore(afterAYear)){
System.out.println("SendTheEmail "+timeToSendEmail.toString());
timeToSendEmail=timeToSendEmail.plusDays(8);
}
}
I wonder why teachers are still teaching the old API (Date, Calendar and SimpleDateFormat), because they have lots of problems and design issues, and they're being replaced by the new APIs. (Java 8 was released in 2014, btw).
Anyway, if you have a GregorianCalendar, you can convert it to the new java.time classes and do the rest with them.
First, you can use the calendar to create an Instant:
Instant instant = Instant.ofEpochMilli(calendar.getTimeInMillis());
The only problem is that, if you create a Calendar and set the day, month and year, it will have the current time (hour/minute/seconds), so the Instant above will have the current time in UTC. If that's ok, you can convert this instant to your timezone:
ZoneId zone = ZoneId.of("America/Sao_Paulo");
ZonedDateTime start = instant.atZone(zone);
I used America/Sao_Paulo, but you can change to the timezone that makes sense to your system. The API uses IANA timezones names (always in the format Region/City, like America/Sao_Paulo or Europe/Berlin).
Avoid using the 3-letter abbreviations (like CST or PST) because they are ambiguous and not standard.
You can get a list of available timezones (and choose the one that fits best your system) by calling ZoneId.getAvailableZoneIds(). You can also use the system's default if you want (ZoneId.systemDefault()), but note that this can be changed without notice, even at runtime, so it's always better to specify which timezone you're using. If you want to work with dates in UTC, you can use the built-in constant ZoneOffset.UTC.
The code above will create a ZonedDateTime with the calendar's date and time adjusted to the specified timezone. Just reminding that, if you do something like this:
Calendar calendar = new GregorianCalendar();
calendar.set(2017, 7, 12);
The date will be equivalent to August 12th 2017 (because months in the Calendar API start at zero, so month 7 is August), and the time will be the current time when the calendar is created.
If you want to specify the hour, you have some options to adjust it:
// change the hour/minute/second to 10:20:45
start = start.with(LocalTime.of(10, 20, 45));
// change just the hour to 10
start = start.withHour(10);
// set to start of the day
start = start.toLocalDate().atStartOfDay(zone);
With this, you can change the time (and also date) fields accordingly. Check the javadoc and Oracle's tutorial to see all the options available. The method atStartOfDay is better because it takes care of Daylight Saving Time changes (depending on DST shift, the day can start at 1AM instead of midnight, and this method takes care of all the details).
If you don't want to rely on Calendar, you can also create the date directly:
// creating August 12th 2017, at 10:00
start = ZonedDateTime.of(2017, 8, 12, 10, 0, 0, 0, zone);
Note that August is month 8 (one of the best and most obvious improvements from the old API).
Now that you have the starting date, you can loop through a whole year and check the dates according to your rules. I'm using the example of sending the email each 16 days and adjust to next monday if it's a weekend:
ZonedDateTime d = start;
// ends in 1 year - this method already takes care of leap years
ZonedDateTime end = start.plusYears(1);
while (end.isAfter(d)) {
d = d.plusDays(16);
if (d.getDayOfWeek() == DayOfWeek.SUNDAY || d.getDayOfWeek() == DayOfWeek.SATURDAY) {
// weekend, adjust to next monday
d = d.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
}
// send email
}
If you're using Java <= 7, you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes.
The only difference from Java 8 is the package names (in Java 8 is java.time and in ThreeTen Backport (or Android's ThreeTenABP) is org.threeten.bp), but the classes and methods names are the same.
As #BasilBourque reminded me in the comments, you can also convert a GregorianCalendar to a ZonedDateTime using the toZonedDateTime() method (this will use the calendar's timezone - usually the system's default, if you don't set it). You can also convert it to an Instant using the toInstant() method. The only restriction is that those methods are only available in Java 8 (so, if you're using ThreeTen Backport, just use the way it's described above).
I have a dates in format such as:
- dd. - dd.MM.yyyy
Based on this information I want to receive from date and to date.
Naive implementation in pseudo code is:
Split the date into first part and second part
Create a SimpleDateFormat for second part
Take a look, whether the number in the first part is higher than the number in a second part.
If it is:
Decrement month for the first date
Create from date which will contain the dd from the first part, decremented month from the second part and year from the second part.
If it isn't:
Create from date which will contain the dd from the first part and month and year from second part.
This solution would probably work most of the time, but it feels rather awkward. Isn't there any better solution?
I'd suggest you to check the package
org.joda.time
In particular the following classes
DateTime
Period
java.time
The java.time framework is built into Java 8 and later. Much of that functionality is back-ported to Java 6 & 7 and to Android.
I provide some scraps of example code here, but untested – never run. Should get you going in the right direction.
Two tricky parts to this problem:
YearThe Question says to assign the year. That is not the case for a stop date in January with a start date that turns out to be in previous month, December. You want the previous year in such a case. Solution is to let java.time subtract a month and handle the Jan-to-Dec math for you.
Month lengthVarious months have different lengths, different number of days, obviously. Keep mind that you cannot try to put day-of-month 31 on to month of April. If your input data is always clean and valid, and our algorithm below is correct, this should be a non-issue. Nevertheless, I would certainly add some exception-catching code to my example code below to trap any attempt to form an invalid date.
I'll skip the string-splitting part, and assume you have a number (the day-of-month) from the first part, and a string of the date from the second part.
long dayOfMonth = Long.longValue( "31" );
That date is not in standard format, so we must specify a formatting pattern. A LocalDate represents a date-only value without time-of-day and without time zone.
DateTimeFormatter formatter = DateTimeFormatter.ofPattern( "dd.MM.yyyy" );
LocalDate stop = LocalDate.parse( "21.05.2016" , formatter );
We can extract the day-of-month to compare.
LocalDate start = null;
int d = localDate.getDayOfMonth();
Do the comparison.
if( dayOfMonth >=d ) { // If start is in previous month…
start = stop.minusMonths( 1 ).withDayOfMonth( dayOfMonth );
} else if (dayOfMonth < d ) { // If start is in same month…
start = stop.withDayOfMonth( dayOfMonth );
} else {
// FIXME: handle impossible condition as error. The 'if' statements are flawed.
}
By the way, the format of this input data is awkward and, frankly, silly. This kind of precious “cleverness” creates extra work, gives opportunity for confusion and errors, is completely needless without providing any benefits, and drives me nuts. If you have any control of this input data I strongly suggest either of two possible changes.
First, if exchanging data within your app, do not use strings. Use objects. Above you have seen the LocalDate object. You could pass those around. Or even define your own class LocalDateRange to house a pair of LocalDate objects. Or see this Question and especially this Answer that talks about using the Google Guava class Range to hold the pair of LocalDate objects.
Secondly, when you must serialize date-time values to strings, use the standard ISO 8601 formats. Such use is simple as the java.time classes by default use these formats when parsing/generating strings. A date-only value should be in YYYY-MM-DD order. A date range interval is a pair of those strings mated with a slash (SOLIDUS) or alternatively a pair of hyphens when a slash is inappropriate (such as file or folder naming within a Unix-related file system).
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.
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();
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
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.
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?
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")!!!
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());