Android/Java - Calculate date difference shows different results - java

public long getDays(){
Date today = new Date ( );
Calendar cal = Calendar.getInstance (TimeZone.getTimeZone("GMT"));
// Set as today
cal.setTime ( today );
System.out.println ( "Today Cal: "+cal.get ( Calendar.YEAR ) + "Y / " + ( cal.get ( Calendar.MONTH ) + 1 ) + "M / " + cal.get ( Calendar.DATE ) + " D" );
Calendar cal2 = Calendar.getInstance (TimeZone.getTimeZone("GMT") );
//Month has offset -1. June = 5
cal2.set ( 2011, 5, 15 );//YY MM DD
System.out.println ( "Start Day Cal2: "+cal2.get ( Calendar.YEAR ) + "Y / " + ( cal2.get ( Calendar.MONTH ) + 1 ) + "M / " + cal2.get ( Calendar.DATE ) + " D" );
long count = 0;
while ( !cal2.after ( cal ) ) {
count++;
//increment date
cal2.add ( Calendar.DATE, 1 );
}
System.out.println ( "Ending Cal2: "+cal2.get ( Calendar.YEAR ) + "Y / " + ( cal2.get ( Calendar.MONTH ) + 1 ) + "M / " + cal2.get ( Calendar.DATE ) + " D" );
return count;
}
This is the code that I am using to calculate the difference in Days between today and 2011 June 15th.
This always works on Eclipse IDE, but when I implement this on Android, it shows 2 different results by random chance.
Screenshot
Most of the times it shows 2405, but sometimes it shows 2406
(Although the date should not have changed as it is 3 AM in the UK now.)
Console output
This is what is shown on System.out.println.
It has the same start date and end date, but by a random chance, while loop counts 1 extra. How?
It only happens on Android.
This is the code showing how the textview is being updated as a widget if it helps.
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
final int count = appWidgetIds.length;
//Set Date Text
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.haruhi_widget);
long days=getDays();
remoteViews.setTextViewText(R.id.textView, days+context.getString(R.string.days));
//Set ImageView
BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false;
Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(),R.drawable.haruhi1,options);
remoteViews.setImageViewBitmap(R.id.imageView,bitmap);
Intent intent = new Intent(context, HaruhiWidgetProvider.class);
intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
remoteViews.setOnClickPendingIntent(R.id.imageView, getPendingSelfIntent(context, KYON_KUN_DENWA));
for (int i = 0; i < count; i++) {
// System.out.println(count+"appWidgetIds[i]");
int widgetId = appWidgetIds[i];
appWidgetManager.updateAppWidget(widgetId, remoteViews);
}
}

tl;dr
ChronoUnit.DAYS.between(
LocalDate.of( 2011 , Month.JUNE , 15 ) ,
LocalDate.now( ZoneId.of( "Africa/Tunis" ) )
)
Problems
Certainly seems like a time zone issue. We cannot be certain as you have not provided us with enough information such as the time zone being used when your code was run.
More importantly, you are using troublesome old date-time classes that were outmoded years ago by the java.time classes.
And you are trying to work with date-only values using date-with-time-of-day classes.
Solution
calculate difference in Days between today and 2011 June 15th.
The LocalDate class represents a date-only value without time-of-day and without time zone.
A time zone is crucial in determining a date. For any given moment, the date varies around the globe by zone. For example, a few minutes after midnight in Paris France is a new day while still “yesterday” in Montréal Québec.
Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).
Always specify your desired/expected time zone explicitly. Omitting the zone means the JVM’s current default time zone is implicitly applied. That default can vary by machine and can even vary during runtime(!). So your results may vary. Instead, always pass the optional ZoneId argument. Doing so has the side benefit of making your intentions clear with more self-documenting code.
ZoneId z = ZoneId.of( "America/Montreal" );
LocalDate today = LocalDate.now( z );
Get the date for 2011 June 15th.
LocalDate ld = LocalDate.of( 2011 , Month.JUNE , 15 ) ;
Calculate elapsed days.
long days = ChronoUnit.DAYS.between( ld , today ) ;
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time (JSR 310) classes.
For earlier Android, the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….

Related

Timer countdown is negative

I have a code of which is used to create a 24 hour countdown.
This code checks if a "date" file exists and if it doesn't it creates one, which contains the date and time in 24 hourse/a day. It then gets the current time and compares the two, to create a countdown from the current date, to the date in the document.
This makes it possible to save the timer and check how far it has come even though the code is "turned off". The only issue is the fact that sometimes the timer turns negative. Like if I run the code from the start with no "date" file created on Monday, right before midnight, lets say Monday at half past eleven at night. Then if I stop the code and run it again when the current date has passed midnight, so it is actually Tuesday, but there is still missing up to 23 hours before it hits the actual goal timer. If this is the case, the time left in the countdown is negative. Like it would show "-1day 23hours 60minutes and 60seconds remaining". But if as an example it is run from scratch past midnight on Tuesday and then relaunch after 30 minutes the same day, there is no issue.
I hope you can understand what the issue is, it is slightly hard to express through text. But I have attached the whole code of mine, which is the exact one I am using and of which is having that issue. The code has comments for every actions happening, so it should be rather easy to understand.
static File dFileD = new File("date.txt");
static String date = "";
public static void main(String[] args) throws ParseException {
Timer tickTock = new Timer();
TimerTask tickTockTask = new TimerTask(){
public void run(){
try {
timFunRun(); //Timer calls method to start the countdown
} catch (ParseException e) {
e.printStackTrace();
}
}
};
tickTock.schedule(tickTockTask, 1000, 1000);
}
static void timFunRun() throws ParseException {
if (!dFileD.exists()){ //if it doesn't exist, first part
//Get current date and time
Calendar startDat = Calendar.getInstance();
System.out.println("Current date: " + startDat.getTime());
//Get that current date and time and then add 1 day
Calendar todAdd = Calendar.getInstance();
todAdd.add(Calendar.DATE, 1);
System.out.println("Date in 1 day: " + todAdd.getTime());
//Create a format for sending date to text file
SimpleDateFormat formDat = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z");
String formatted = formDat.format(todAdd.getTime());
System.out.println("Formatted: " + formatted);
try{
PrintWriter dW = new PrintWriter("date.txt");
dW.println(formatted);
dW.close();
} catch (IOException e) {
}
System.out.println(formDat.parse(formatted));
} else { //if it does exist, second part
//Get current date and time
Calendar currentDeT = Calendar.getInstance();
System.out.println("Current date: " + currentDeT.getTime());
SimpleDateFormat formDat2 = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z");
Date dateFroText = null; //Get the "goal" date
try {
Scanner dateRead = new Scanner(dFileD);
while (dateRead.hasNextLine()) {
date = dateRead.nextLine();
dateFroText = formDat2.parse(date);
System.out.println("Date from text new format: " + dateFroText);
}
dateRead.close();
} catch (Exception e) {
System.out.println("Error!");
}
if (dateFroText != null){ //method to compare the current date and the goal date
Calendar dateFromTxtCal = Calendar.getInstance();
dateFromTxtCal.setTime(dateFroText);
int yearDiff = dateFromTxtCal.get(Calendar.YEAR) - currentDeT.get(Calendar.YEAR);
int dayDiff = ((yearDiff*365) + dateFromTxtCal.get(Calendar.DAY_OF_YEAR)) - currentDeT.get(Calendar.DAY_OF_YEAR);
dayDiff--;
int hourDiffer = dateFromTxtCal.get(Calendar.HOUR_OF_DAY)+23 - currentDeT.get(Calendar.HOUR_OF_DAY);
int minuDiff = dateFromTxtCal.get(Calendar.MINUTE)+60 - currentDeT.get(Calendar.MINUTE);
int secoDiff = dateFromTxtCal.get(Calendar.SECOND)+60 - currentDeT.get(Calendar.SECOND);
System.out.println(dayDiff + " days " + hourDiffer + " hours " + minuDiff +" minutes " + secoDiff + "seconds remaining");
}
}
}
Avoid legacy date-time classe
You are working too hard. And you are using troublesome old date-time classes now obsoleted and supplanted by the java.time classes.
Work in UTC
Also, if you only care about the next 24 hours, then no need for time zones. Just use UTC.
Instant
The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction).
Instant instantNow = Instant.now();
Duration
A span of time unattached to the timeline is represented by the Duration or Period classes.
Duration duration = Duration.ofHours( 24 );
You can perform date-time math, adding a Duration to an Instant. The java.time classes use immutable objects, so the result of such manipulations is a fresh object with values based on the original.
Instant instantLater = instantNow.plus( duration );
ISO 8601
To serialize date-time values such as those to text, use the standard ISO 8601 formats. The java.time classes use ISO 8601 by default when generating and parsing strings.
String output = instantNow.toString();
2017-04-03T03:18:48.183Z
Calculate remaining time
To get the remaining time, let java.time do the math.
Duration remaining = Duration.between( Instant.now() , instantLater );
To report that in standard ISO 8601 format, call toString. The format for durations is PnYnMnDTnHnMnS. The P marks the beginning (for Period), and the T separates any years-months-dates from hours-minutes-seconds.
String outputRemaining = remaining.toString();
PT23H34M22S
To generate a longer string, in Java 9 call the to…Part method for each unit (hours, minutes, seconds). Oddly those methods were omitted from the original java.time.Duration class in Java 8. You could look to the source code of Java 9 to write similar code.
Or more simply, manipulate the standard string. Delete the PT. Replace the H with hours and so on. Do S first to avoid the plural s in the other two words. Admittedly this is kind of a hack, but it works thanks to some good luck in the occurrence of letters is the English spelling of hours-minutes-seconds.
String output = remaining.toString()
.replace( "PT" , "" )
.replace( "S" , " seconds " )
.replace( "H" , " hours " )
.replace( "M" , " minutes " ) ;
23 hours 34 minutes 22 seconds
ZonedDateTime
If you want to display the target date-time in the user's desired/expected time zone, apply a ZoneId to get a ZonedDateTime object.
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone( z );
To generate a string in standard format, call toString. Actually the ZonedDateTime class extends the standard by appending the name of the time zone in square brackets.
To generate strings in other formats, search Stack Overflow for many examples of DateTimeFormatter class.
Converting to java.util.Date
The Timer class has not yet been updated to work with the java.time types. So convert back to a Date object via new methods added to the old classes, in this case from.
java.util.Date date = java.util.Date.from( instantLater );
Or use a count of milliseconds from the Duration object.
long milliseconds = duration.toMillis() ;
ScheduledExecutorService
FYI, the Timer and TimeTask classes have been supplanted by the Executors framework. Specifically for your purpose, the ScheduledExecutorService. Search Stack Overflow for many examples and discussions.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
Where to obtain the java.time classes?
Java SE 8 and SE 9 and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
The ThreeTenABP project adapts ThreeTen-Backport (mentioned above) for Android specifically.
See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

Calculate endTime using startTime and testDuration

I have the test start time (say 9:05:30) and total duration (say 5000 seconds) that a test should run.How to calculate the end time from start time and end time?
If you're using something like Instant, ZonedDateTime or LocalDateTime from the Java 8 time API, you can use plusSeconds:
Instant startTime = ...
Instant endTime = startTime.plusSeconds(5000);
If you're using Date (oh, the horrors...), you can simply use getTime:
Date startTime = ...
Date endTime = new Date(startTime.getTime() + TimeUnit.SECONDS.toMillis(5000));
In javascipt you can do
console.time('testSomeCall');
//code here
console.timeEnd('testSomeCall');
in other languages usually you get the time or timestamp before your test and then after and do end - init, like this in this for java
long timeInit = System.currentTimeMillis();
//some code here
long timeEnd = System.currentTimeMillis();
System.out.println("Ttotal time: " + (timeEnd - timeInit));
String myTime = "9:05:20";
// before calculation
Date tempStartTime = new SimpleDateFormat("HH:mm:ss").parse(myTime);
int hours = tempStartTime.getHours();
int minutes = tempStartTime.getMinutes();
int seconds = tempStartTime.getSeconds();
int elapsedSeconds = 5000;
// add seconds
int totalSeconds = seconds + elapsedSeconds;
// after calculation
Date tempEndTime = new SimpleDateFormat("HH:mm:ss").parse(hours + ":" + minutes + ":" + totalSeconds);
hours = tempEndTime.getHours();
minutes = tempEndTime.getMinutes();
seconds = tempEndTime.getSeconds();
System.out.println(hours + ":" + minutes + ":" + seconds);
// Output is 10:28:40
How can 09:05:5020 be parsed as Date?
the value is successfully parsed as the 5020th seconds, simply rolling over to next minute after each 60 seconds to accommodate the Out-Of-Bounds value. If you want to prevent this, call setLenient(false); on a DateFormat object before parsing (leniency is true by default).
The Answer by Andy Turner is correct about using java.time rather than the old date-time classes. Here's more specific detail.
java.time
The java.time framework is built into Java 8 and later. These classes supplant the old troublesome date-time classes such as java.util.Date, .Calendar, & java.text.SimpleDateFormat.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations.
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport and further adapted to Android in ThreeTenABP.
Instant
If just programmatically getting 5,000 seconds later from now, use the Instant object as shown in Turner’s Answer. An Instant is a moment on the timeline in UTC with a resolution up to nanoseconds.
Instant later = Instant.now().plusSeconds( 5_000 );
LocalTime
The LocalTime class represents a time-of-day without a date and without a time zone. So this works only for generic 24-hour days, not realistic days with time zones that have anomalies such as Daylight Saving Time (DST).
LocalTime lt = LocalTime.parse( "09:05:30" );
LocalTime later = lt.plusSeconds( 5_000 );
If hitting midnight, the result will roll-over into the early hours of the day starting with hour 00, then 01, and so on.
ZonedDateTime
If you want a realistic value that respects DST and so on, use ZonedDateTime.
ZoneId zoneId = ZoneId.of( "America/Montreal" );
LocalDate tomorrow = LocalDate.now( zoneId ).plusDays( 1 );
LocalTime lt = LocalTime.parse( "09:05:30" );
ZonedDateTime tomorrowAround9Am = ZonedDateTime.of( tomorrow , lt , zoneId 0;
ZonedDateTime later = tomorrowAround9Am.plusSeconds( 5_000 );

Creating a DateTime from two other dates

Basically I want to see if someones birthday is within 3 months of todays date. I am going to use Days to do this and just say "90" days.
My thoughts are as follows:
I will set a new datetime as todays date and then grab the DOB of the person in question.
I will then want to take the day and month from the DOB and the year from Todays date.
Then these days, months and years will be merged into one new date.
For example:
DOB 04/05/1987
Today 10/05/2013
NewBirth 04/05/2013
How can I achieve the part where I grab the days/months from one date, years from another, and put these into one date?
(Only key factors, im aware this rule wouldn't run)
import org.joda.time.ReadableInstant;
import org.joda.time.DateTime;
import org.joda.time.Days;
import org.joda.time.Months;
import org.joda.time.Years;
rule"Blah"
salience 1
when
Proposer($dob : dateOfBirth)
then
DateTime NewBirth = new DateTime()
DateTime today = new DateTime();
#grab DOB day and month
#grab Todays year
#turn "NewBirth" into a combination of the above 2 lines
int $birthday = (Days.daysBetween((ReadableInstant)today,(ReadableInstant)NewBirth).getDays());
If ($birthday <= 90){
logger.info("HURRRAAAYYYYYY");
}
end
I would do it with the standard JDK Calendar
boolean isWithin3Month(int y, int m, int d) {
Calendar now = Calendar.getInstance();
Calendar birthday = new GregorianCalendar(y, m, d);
int currentMonth = now.get(Calendar.MONTH);
int birthDayMonth = birthday.get(Calendar.MONTH);
int monthDiff;
if (birthDayMonth < currentMonth) { // eg birth = Jan (0) and curr = Dec (11)
monthDiff = 12 - currentMonth + birthDayMonth;
} else {
monthDiff = birthDayMonth - currentMonth;
}
if (monthDiff < 0 || monthDiff > 3) {
return false;
} else if (monthDiff == 0) {
return birthday.get(Calendar.DATE) >= now.get(Calendar.DATE);
}
return true;
}
java.time
The Joda-Time project is now in maintenance mode, with the team advising migration to the java.time classes.
LocalDate
The LocalDate class represents a date-only value without time-of-day and without time zone.
A time zone is crucial in determining a date. For any given moment, the date varies around the globe by zone. For example, a few minutes after midnight in Paris France is a new day while still “yesterday” in Montréal Québec.
ZoneId z = ZoneId.of( "America/Montreal" );
LocalDate today = LocalDate.now( z );
You apparently want to know if the birthday anniversary lands between today and 90 days from today. So determine that 90 day limit.
LocalDate ninetyDaysFromToday = today.plusDays( 90 );
Get the birthdate.
LocalDate birthdate = LocalDate.of( 1987 , Month.APRIL , 5 ) ;
MonthDay
The MonthDay class represents, well, a month and a day-of-month, without any year. You can adjust into a year to get a date. Perfect for adjusting that birthday into this year.
If the birthday of this year is already past, then we need to consider next year’s birthday, as the 90 day limit may wrap over into the new year.
MonthDay mdBirthday = MonthDay.from( birthdate );
MonthDay mdToday = MonthDay.from( today );
int y = mdBirthday.isBefore( mdToday ) ? ( today.getYear()+1 ) : today.getYear() ;
LocalDate nextBirthday = mdBirthday.atYear( y );
Boolean nextBirthdayIsWithinNextNinetyDays = nextBirthday.isBefore( ninetyDaysFromToday );
Or another way to do the same.
LocalDate nextBirthday = MonthDay.from( birthdate ).atYear( today.getYear() ) ; // Possibly the next birthday, not yet sure.
if( nextBirthday.isBefore( today ) ) {
// This year’s birthday is past, so increment the year to get next birthday.
nextBirthday = nextBirthday.plusYears( 1 );
}
Boolean nextBirthdayIsWithinNextNinetyDays = nextBirthday.isBefore( ninetyDaysFromToday );
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, .Calendar, & java.text.SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to java.time.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
Where to obtain the java.time classes?
Java SE 8 and SE 9 and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
The ThreeTenABP project adapts ThreeTen-Backport (mentioned above) for Android specifically.
See How to use….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
Try
DateTime newBirth = new DateTime(today.year(), $dob.monthOfYear(), $dob.dayOfMonth(), 00, 00);
instead of the parameterless constructer at the beginning of your then statement.
Ended up managing to do it with Jodatime,
rule"Less than 3months before Birthday Discount"
when
Proposer($dob : dateOfBirth)
then
DateTime today = new DateTime();
DateTime newBirth = new DateTime(today.year().get()+"-"+$dob.monthOfYear().get()+"-"+$dob.dayOfMonth().get());
int $birthday = (Days.daysBetween((ReadableInstant)today,(ReadableInstant)newBirth).getDays());
if($birthday <=90 && $birthday>0){
logger.info("discount applied");
}
end

Joda Time - Get all weeks of a year

is there a way to get all weeks of a year plus start and ending days of every week ?
(With Joda-Time)
something like this (2012) :
week : 21
start: 21.05.2012
ending : 27.05.12
Thanks for your help
Try this:
SimpleDateFormat df = new SimpleDateFormat("dd.MM.yyyy");
Period weekPeriod = new Period().withWeeks(1);
DateTime startDate = new DateTime(2012, 1, 1, 0, 0, 0, 0 );
DateTime endDate = new DateTime(2013, 1, 1, 0, 0, 0, 0 );
Interval i = new Interval(startDate, weekPeriod );
while(i.getEnd().isBefore( endDate)) {
System.out.println( "week : " + i.getStart().getWeekOfWeekyear()
+ " start: " + df.format( i.getStart().toDate() )
+ " ending: " + df.format( i.getEnd().minusMillis(1).toDate()));
i = new Interval(i.getStart().plus(weekPeriod), weekPeriod);
}
Note that the week numbers start at 52 and then go from 1 - 51, since Jan 1 isn't on a Sunday.
If instead you want to see the dates of each Monday-Sunday week:
SimpleDateFormat df = new SimpleDateFormat("dd.MM.yyyy");
Period weekPeriod = new Period().withWeeks(1);
DateTime startDate = new DateTime(2012, 1, 1, 0, 0, 0, 0 );
while(startDate.getDayOfWeek() != DateTimeConstants.MONDAY) {
startDate = startDate.plusDays(1);
}
DateTime endDate = new DateTime(2013, 1, 1, 0, 0, 0, 0);
Interval i = new Interval(startDate, weekPeriod);
while(i.getStart().isBefore(endDate)) {
System.out.println("week : " + i.getStart().getWeekOfWeekyear()
+ " start: " + df.format(i.getStart().toDate())
+ " ending: " + df.format(i.getEnd().minusMillis(1).toDate()));
i = new Interval(i.getStart().plus(weekPeriod), weekPeriod);
}
Joda-Time is in maintenance mode
FYI, the Joda-Time project is now in maintenance mode, with the team advising migration to the java.time classes. See Tutorial by Oracle.
Define ‘week’
You can define a week in different ways.
I will assume you mean the standard ISO 8601 week. Week number 1 has the first Thursday of the year, starts on a Monday, and a week-based year has either 52 or 53 weeks. A few days at the end or beginning of the calendar year may land in the other week-based year.
java.time
The modern approach uses the java.time classes, and their extension found in the ThreeTen-Extra project.
From ThreeTen-Extra, use the YearWeek class.
YearWeek start = YearWeek.of( 2017 , 1 ) ; // First week of the week-based year 2017.
Get the number of weeks in this week-based year, 52 or 53.
int weeks = start.lengthOfYear() ;
…or…
int weeks = ( start.is53WeekYear() ) ? 53 : 52 ;
Loop for each week of the year. For each YearWeek, ask it to produce a LocalDate for the beginning and ending of that week.
List<String> results = new ArrayList<>( weeks ) ;
YearWeek yw = start ;
for( int i = 1 , i <] weeks , i ++ ) {
String message = "Week: " + yw + " | start: " + yw.atDay( DayOfWeek.MONDAY ) + " | stop: " + yw.atDay( DayOfWeek.SUNDAY ) ;
results.add( message ) ;
// Prepare for next loop.
yw = yw.plusWeeks( 1 ) ;
}
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
The ThreeTenABP project adapts ThreeTen-Backport (mentioned above) for Android specifically.
See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
Never used Joda Time.
I would do something like this:
Create a class that has the weeknumber and two DateTimes (start, end)
Create a List of this class
Iterate over the year (week per week) and save the current week in the list
That's the way I would do this with the standard java calendar api. Probably Joda Time is a little bit easier, I don't know.

Android Calendar problem with day of the week

I'm trying to list all days of the week for current week from Monday to Sunday. For example, today (day of this posting) is September 4th, 2011 and it's Sunday.
I'm starting calendar and setting first day of the week to Monday:
Calendar cal = Calendar.getInstance();
cal.setFirstDayOfWeek(Calendar.MONDAY);
When I check day of the month, I get correct result:
int check = cal.get(Calendar.DAY_OF_MONTH);
// check is equal to 4
But when I set weekday to Monday, it jumps to the next week instead of returning Monday of this week:
cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
int mon = cal.get(Calendar.DAY_OF_MONTH);
// mon is equal to 5, when expected to be 29 (last Monday of August)
Even setting weekday to Sunday returns next Sunday and not today.
Can someone explain why it works that way and what's the best way to solve this problem?
In fact, when I check my own tests, it seems to work as expected, except when the date is not set again:
Display 4-29:
Calendar cal = Calendar.getInstance();
cal.setFirstDayOfWeek(Calendar.MONDAY);
cal.setMinimalDaysInFirstWeek(4);
cal.set(2011, 8, 4);
int test = cal.get(Calendar.DAY_OF_MONTH);
cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
int mon = cal.get(Calendar.DAY_OF_MONTH);
bTest.setText("" + test + "-" + mon);
Display 5-5:
Calendar cal = Calendar.getInstance();
cal.setFirstDayOfWeek(Calendar.MONDAY);
cal.setMinimalDaysInFirstWeek(4);
cal.set(2011, 8, 5);
int test = cal.get(Calendar.DAY_OF_MONTH);
cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
int mon = cal.get(Calendar.DAY_OF_MONTH);
bTest.setText("" + test + "-" + mon);
Display 14-12:
Calendar cal = Calendar.getInstance();
cal.setFirstDayOfWeek(Calendar.MONDAY);
cal.setMinimalDaysInFirstWeek(4);
cal.set(2011, 8, 14);
int test = cal.get(Calendar.DAY_OF_MONTH);
cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
int mon = cal.get(Calendar.DAY_OF_MONTH);
bTest.setText("" + test + "-" + mon);
So, this doesn't work:
Calendar cal = Calendar.getInstance();
cal.setFirstDayOfWeek(Calendar.MONDAY);
cal.setMinimalDaysInFirstWeek(4);
//cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH));
int test = cal.get(Calendar.DAY_OF_MONTH);
cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
int mon = cal.get(Calendar.DAY_OF_MONTH);
bTest.setText("" + test + "-" + mon); // Display 4-5
and this works:
Calendar cal = Calendar.getInstance();
cal.setFirstDayOfWeek(Calendar.MONDAY);
cal.setMinimalDaysInFirstWeek(4);
// Workaround
cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH));
int test = cal.get(Calendar.DAY_OF_MONTH);
cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
int mon = cal.get(Calendar.DAY_OF_MONTH);
bTest.setText("" + test + "-" + mon); // Display 4-29
and this works too:
Calendar cal = Calendar.getInstance();
cal.setFirstDayOfWeek(Calendar.MONDAY);
cal.setMinimalDaysInFirstWeek(4);
// Workaround
cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH));
cal.get(Calendar.DAY_OF_MONTH);
cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
int mon = cal.get(Calendar.DAY_OF_MONTH);
bTest.setText("" + mon); // Display 29
But this one doesn't:
Calendar cal = Calendar.getInstance();
cal.setFirstDayOfWeek(Calendar.MONDAY);
cal.setMinimalDaysInFirstWeek(4);
// Workaround
cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH));
cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
int mon = cal.get(Calendar.DAY_OF_MONTH);
bTest.setText("" + mon); // Display 5
tl;dr
Use LocalDate, never Calendar.
LocalDate.now( ZoneId.of( "Africa/Tunis" ) )
.with( TemporalAdjusters.previousOrSame( DayOfWeek.MONDAY ) )
.plusDays( i ) )
java.time
Avoid the troublesome old legacy class Calendar as it is now legacy, supplanted by the java.time classes (specifically ZonedDateTime).
For date-only values without time-of-day, use LocalDate rather than a date+time type like Calendar or ZonedDateTime. The LocalDate class represents a date-only value without time-of-day and without time zone.
A time zone is crucial in determining a date. For any given moment, the date varies around the globe by zone. For example, a few minutes after midnight in Paris France is a new day while still “yesterday” in Montréal Québec.
If no time zone is specified, the JVM implicitly applies its current default time zone. That default may change at any moment, so your results may vary. Better to specify your desired/expected time zone explicitly as an argument.
Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "America/Montreal" ) ;
LocalDate today = LocalDate.now( z ) ;
If you want to use the JVM’s current default time zone, ask for it and pass as an argument. If omitted, the JVM’s current default is applied implicitly. Better to be explicit, as the default may be changed at any moment during runtime by any code in any thread of any app within the JVM.
ZoneId z = ZoneId.systemDefault() ; // Get JVM’s current default time zone.
Or specify a date. You may set the month by a number, with sane numbering 1-12 for January-December.
LocalDate ld = LocalDate.of( 1986 , 2 , 23 ) ; // Years use sane direct numbering (1986 means year 1986). Months use sane numbering, 1-12 for January-December.
Or, better, use the Month enum objects pre-defined, one for each month of the year. Tip: Use these Month objects throughout your codebase rather than a mere integer number to make your code more self-documenting, ensure valid values, and provide type-safety.
LocalDate ld = LocalDate.of( 1986 , Month.FEBRUARY , 23 ) ;
DayOfWeek
For day-of-week, use the DayOfWeek enum class. It offers seven instances, one for each day of the week, Monday-Sunday.
DayOfWeek dow = ld.getDayOfWeek() ; // Get an enum representing the day-of-week of this date, such as `DayOfWeek.MONDAY`.
Adjusting date
We need find the previous Monday, or stick with today’s date if already a Monday. To move to such dates, use the TemporalAdjusters.previousOrSame implementation of TemporalAdjuster.
TemporalAdjuster ta = TemporalAdjusters.previousOrSame( DayOfWeek.MONDAY ) ;
LocalDate previousOrSameMonday = ld.with( ta ) ;
Collect your desired dates by incrementing with a call to LocalDate.plusDays(). Notice how java.time uses immutable objects. We get a fresh object based on the values of the original rather than mutating (altering) the original.
// Hard-coded `7` is the seven days in a week.
List< LocalDate > dates = new ArrayList<>( 7 ) ;
for( int i = 0 , i < 7 , i ++ ) {
LocalDate localDate = previousOrSameMonday.plusDays( i ) ;
dates.add( localDate ) ;
}
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
UPDATE: The Joda-Time project is now in maintenance mode, with the team advising migration to the java.time classes. This section left for history.
Joda-Time
what's the best way to solve this problem?
The best way is to avoid using the notoriously troublesome java.util.Date & .Calendar classes, and instead use the Joda-Time library. Joda-Time works in Android.
Joda-Time offers the LocalDate class for date-only values without any time or time zone.
Example Code
Here is some example code using Joda-Time 2.3.
LocalDate localDate = new LocalDate( 2011, DateTimeConstants.SEPTEMBER, 4 );
LocalDate firstDateOfWeek = localDate.withDayOfWeek( DateTimeConstants.MONDAY );
for ( int i = 0; i < 7; i++ ) {
LocalDate someDateOfWeek = firstDateOfWeek.plusDays( i );
System.out.println( "someDateOfWeek: " + someDateOfWeek + " le jour de la semaine: " + someDateOfWeek.dayOfWeek().getAsText( Locale.CANADA_FRENCH ) );
}
When run…
someDateOfWeek: 2011-08-29 le jour de la semaine: lundi
someDateOfWeek: 2011-08-30 le jour de la semaine: mardi
someDateOfWeek: 2011-08-31 le jour de la semaine: mercredi
someDateOfWeek: 2011-09-01 le jour de la semaine: jeudi
someDateOfWeek: 2011-09-02 le jour de la semaine: vendredi
someDateOfWeek: 2011-09-03 le jour de la semaine: samedi
someDateOfWeek: 2011-09-04 le jour de la semaine: dimanche
Week Number
Bonus tip: If you want the week number as defined by the ISO 8601 standard, call the weekOfWeekYear method. Like this:
int weekNumber = firstDateOfWeek.getWeekOfWeekyear();
Your date is in week 35.
Humans must not use language of android beings, just kidding, date entering, is another one nail to java coffin.
core of this misunderstanding problem is bad documentation and two facts, months numbered from 0, and year counts from 1900, but not in Calendar and his descendants.
and one more fact, in Date Sunday is 0, but in Calendar Sunday is 1.
//THIS WORKS CORRECTLY
Date my = new Date(1986 - 1900, 04 - 1, 26);
System.out.println(my);
System.out.println(my.getDay());
Calendar cal = Calendar.getInstance(TimeZone.getDefault());
cal.set(1986, 04 - 1, 26);
System.out.println(cal.getTime());
System.out.println(cal.get(Calendar.DAY_OF_WEEK)-Calendar.SUNDAY);
another, much more convenient way
//ONE AND ONLY, HUMAN FRIENDLY WAY TO ENTER DATE INTO JAVA
String date = "1986-04-26:01:23:47";
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd:HH:mm:SS");
Date convertedDate = (Date) formatter.parse(date);
System.out.println(convertedDate);
quite simple, is not it?

Categories

Resources