How to generate an array of Date objects in Kotlin? - java

I want to generate an array of date objects Kotlin style, from current day descending each 5 days programmatically:
{now, 5_days_ago, 10_days_ago, etc..}
private fun dateArray() : ArrayList<Date> {
val date = Date()
val date2 = Date(date.time - 432000000)
val date3 = Date(date2.time - 432000000)
val date4 = Date(date3.time - 432000000)
val date5 = Date(date4.time - 432000000)
val date6 = Date(date5.time - 432000000)
val date7 = Date(date6.time - 432000000)
val date8 = Date(date7.time - 432000000)
val date9 = Date(date8.time - 432000000)
val dateA = Date(date9.time - 432000000)
return arrayListOf(date, date2, date3, date4, date5, date6, date7, date8, date9, dateA)
}
This way is to much overheaded. I bet Kotlin offers an elegant way?

java.time
Here’s a simple pure Java solution. Like others I am recommending that you use java.time, the modern Java date and time API, for your date work.
Period step = Period.ofDays(-5);
int numberOfDates = 10;
Period totalPeriod = step.multipliedBy(numberOfDates);
LocalDate today = LocalDate.now(ZoneId.of("America/Rosario"));
List<LocalDate> dates = today.datesUntil(today.plus(totalPeriod), step)
.collect(Collectors.toList());
System.out.println(dates);
Output:
[2020-09-14, 2020-09-09, 2020-09-04, 2020-08-30, 2020-08-25,
2020-08-20, 2020-08-15, 2020-08-10, 2020-08-05, 2020-07-31]
I trust that you can translate to Kotlin and maybe even refine it further in Kotlin.
It’s not well documented that you may use the two-arg LocalDate.datesUntil() with a negative period, but at least it works on my Java 11.
Sorry to say, your solution in the question not only has more code than needed, it is also incorrect. Subtracting 432 000 000 milliseconds each time assumes that a day is always 24 hours. Because of summer time (DST) and other time anomalies a day may be 23 or 25 hours or something in between. By using LocalDate we are free of such issues. You may also use for example ZonedDateTime of LocalDateTime instead if you want to include time of day, they work fine across summer time transitions too.
Link: Oracle tutorial: Date Time explaining how to use java.time.

I recommend you switch from the outdated and error-prone java.util date-time API to the modern java.time date-time API. Learn more about the modern date-time API from Trail: Date Time. If your Android API level is still not compliant with Java8, check How to use ThreeTenABP in Android Project and Java 8+ APIs available through desugaring.
Do it as follows using the Java modern date-time API:
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
// Tests
System.out.println(getPastDaysOnIntervalOf(10, 5));// 10 days in past at an interval of 5 days
System.out.println(getPastDaysOnIntervalOf(5, 10));// 5 days in past at an interval of 10 days
}
static List<LocalDate> getPastDaysOnIntervalOf(int times, int interval) {
// The list to be populated with the desired dates
List<LocalDate> list = new ArrayList<>();
// Today
LocalDate date = LocalDate.now();
for (int i = 1; i <= times; i++) {
list.add(date);
date = date.minusDays(interval);
}
// Return the populated list
return list;
}
}
Output:
[2020-09-14, 2020-09-09, 2020-09-04, 2020-08-30, 2020-08-25, 2020-08-20, 2020-08-15, 2020-08-10, 2020-08-05, 2020-07-31]
[2020-09-14, 2020-09-04, 2020-08-25, 2020-08-15, 2020-08-05]
Using legacy API:
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
public class Main {
public static void main(String[] args) {
// Tests
System.out.println(getPastDaysOnIntervalOf(10, 5));// 10 days in past at an interval of 5 days
System.out.println(getPastDaysOnIntervalOf(5, 10));// 5 days in past at an interval of 10 days
}
static List<Date> getPastDaysOnIntervalOf(int times, int interval) {
// The list to be populated with the desired dates
List<Date> list = new ArrayList<>();
// Today
Calendar cal = Calendar.getInstance();
Date date = cal.getTime();
for (int i = 1; i <= times; i++) {
list.add(date);
cal.add(Calendar.DATE, -interval);
date = cal.getTime();
}
// Return the populated list
return list;
}
}

Related

How to set correct am/pm times for time picker in Android Studio?

I'm trying to create a time converter based on some sample cities and their respective time zones. I'm retrieving the current time in UTC, then adding or subtracting according to the offset from UTC for each timezone, then I'm adding or subtracting 12 to convert the time to its corresponding 12-hour format so it could be either am or pm. Then this information is showed on a TimePicker when the user selects a city from a spinner.
Now the problem is that I'm getting the correct hour, but for some time zones the am\pm is backwards. So for example, my local time is EST, and I want to convert to PST. Let's say it's 7pm, and I want to know the time in LA. Instead of showing 4pm, it shows 4am.
So I'm having trouble "correcting" the times. I used .HOUR_OF_DAY which I think is supposed to account for Daylight Saving, and I tried using HOUR but that wouldn't solve the problem and would just set the time back one hour.
The corrective math with the twelve hours is needed to convert the 24-hour format to 12 -hour, but this doesn't work as I intended because, as I mentioned, while it does set to the correct hour, it doesn't account for the right am/pm according to the actual time.
Also, .setIs24HourView is set to false.
Anyway, here's the function that takes care of this functionality:
public int convertTime(String city)
{
//Result of taking in the UTC time and adding/subtracting the offset
int offset = 0;
//gets the calender instance of time with GMT standard, then getting hour of day
Calendar c = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
int UTC = c.get(Calendar.HOUR_OF_DAY);
//set offset according to city
switch(city)
{
case "New York":
offset = UTC-4;
break;
case "London":
offset = UTC+1;
break;
case "Los Angeles":
offset = UTC-7;
break;
case "Dubai":
offset= UTC+4;
break;
case "Paris":
offset = UTC+2;
break;
case "Moscow":
offset = UTC+3;
break;
case "Cairo":
offset = UTC+2;
break;
case "Hong Kong":
offset = UTC+8;
break;
case "Beijing":
offset = UTC+8;
break;
case "New Delhi":
offset= UTC+5;
break;
case "Mexico City":
offset = UTC-5;
break;
case "Brasilia":
offset = UTC-3;
break;
}
//if the offset is in the AM
if(offset < 12)
{
//set am
offset = offset+12;
}
//if the offset is in the PM
else if(offset > 12)
{
//set pm
offset = offset-12;
}
else
//its twelve o'clock
offset = 12;
return offset;
}
And here's how it would appear in the app, for visualization:
Time Converter
EDIT: Sorry, I should have added this as well. So the offset is returning the "conversion factor", which I used in the onItemSelected event for the spinner. So when the user selects an item from the spinner, this function reads the entry, and sets the time according to the offset value (that is, the hour, and minute too, but that's statically set since it will always return the correct minute):
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id)
{
if(convertSpinner.getSelectedItemPosition() == 0)
{
//display current/local time
int hour = c.get(Calendar.HOUR_OF_DAY);
convertTime.setHour(hour);
//currentTime.setHour(hour);
}
else if(convertSpinner.getSelectedItemPosition()== 1)
convertTime.setHour(conversionFactory("New York"));
else if(convertSpinner.getSelectedItemPosition()== 2)
convertTime.setHour(conversionFactory("London"));
else if(convertSpinner.getSelectedItemPosition()== 3)
convertTime.setHour(conversionFactory("Los Angeles"));
//... same processs for the other cities, shortened for obvious reasons
else
convertTime.setHour(12);
//set the minute
int minute = c.get(Calendar.MINUTE);
convertTime.setMinute(minute);
}
Also here's my main:
private TimePicker currentTime, convertTime;
private Spinner convertSpinner;
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState)
{
View v= inflater.inflate(R.layout.fragment_time, container, false);
convertTime = v.findViewById(R.id.convert_clock);
convertSpinner = v.findViewById(R.id.convert_spinner);
convertTime.setIs24HourView(false);
convertTime.setClickable(false);
//for convert spinner
ArrayAdapter<CharSequence> adapter2 = ArrayAdapter.createFromResource(getActivity(),R.array.time_cities, android.R.layout.simple_spinner_item);
adapter2.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
convertSpinner.setAdapter(adapter2);
convertSpinner.setOnItemSelectedListener(this);
return v;
}
You don't need to reinvent the wheel.
Instead of putting so much of error-prone complex logic, you should use the OOTB (Out-Of-The-Box) date-time API. Both, the modern as well the legacy API, have much easier ways to do what you are trying to do with your complex custom logic.
However, the legacy date-time API i.e. the ones from java.util and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern date-time API. For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.
Defining a timezone requires not just the City but also the Continent.
The standard format to represent a timezone string is Continent/City.
Using the modern API:
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
public class Main {
public static void main(String... args) {
// Test
System.out.println(getOffset("Europe/London"));
System.out.println(getOffset("Africa/Johannesburg"));
System.out.println(getOffset("America/Chicago"));
System.out.println(getOffset("Asia/Calcutta"));
}
public static ZoneOffset getOffset(String zoneId) {
return ZonedDateTime.now(ZoneId.of(zoneId)).getOffset();
}
}
Output:
Z
+02:00
-06:00
+05:30
Note that Z stands for Zulu time which specifies UTC (which has timezone offset of +00:00 hours).
Using legacy API:
import java.util.TimeZone;
public class Main {
public static void main(String... args) {
// Test
System.out.println(getOffset("Europe/London"));
System.out.println(getOffset("Africa/Johannesburg"));
System.out.println(getOffset("America/Chicago"));
System.out.println(getOffset("Asia/Calcutta"));
}
public static String getOffset(String zoneId) {
int offset = TimeZone.getTimeZone(zoneId).getRawOffset();// milliseconds to be added to UTC
int seconds = offset / 1000;
int hours = seconds / 3600;
int minutes = (seconds % 3600) / 60;
return "GMT" + (offset >= 0 ? "+" : "-") + String.format("%02d", Math.abs(hours)) + ":"
+ String.format("%02d", minutes);
}
}
Output:
GMT+00:00
GMT+02:00
GMT-06:00
GMT+05:30
How to convert a date-time from one timezone to the other:
With the modern date-time API, you can use ZonedDateTime#withZoneSameInstant and OffsetDateTime#withOffsetSameInstant to get the ZonedDateTime and OffsetDateTime respectively in the specified timezone.
Demo of ZonedDateTime
import java.time.ZoneId;
import java.time.ZonedDateTime;
public class Main {
public static void main(String... args) {
// Test
ZonedDateTime zdt = ZonedDateTime.now(ZoneId.systemDefault());
System.out.println(zdt);
System.out.println(getZonedDateTimeWithZoneId(zdt, "Europe/London"));
System.out.println(getZonedDateTimeWithZoneId(zdt, "Africa/Johannesburg"));
System.out.println(getZonedDateTimeWithZoneId(zdt, "America/Chicago"));
System.out.println(getZonedDateTimeWithZoneId(zdt, "Asia/Calcutta"));
}
public static ZonedDateTime getZonedDateTimeWithZoneId(ZonedDateTime zdt, String zoneId) {
return zdt.withZoneSameInstant(ZoneId.of(zoneId));
}
}
Output:
2020-12-28T20:03:54.093476Z[Europe/London]
2020-12-28T20:03:54.093476Z[Europe/London]
2020-12-28T22:03:54.093476+02:00[Africa/Johannesburg]
2020-12-28T14:03:54.093476-06:00[America/Chicago]
2020-12-29T01:33:54.093476+05:30[Asia/Calcutta]
Demo of OffsetDateTime
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
public class Main {
public static void main(String... args) {
// Test
OffsetDateTime odt = OffsetDateTime.now(ZoneId.systemDefault());
System.out.println(odt);
System.out.println(getOffsetDateTimeWithZoneId(odt, "Europe/London"));
System.out.println(getOffsetDateTimeWithZoneId(odt, "Africa/Johannesburg"));
System.out.println(getOffsetDateTimeWithZoneId(odt, "America/Chicago"));
System.out.println(getOffsetDateTimeWithZoneId(odt, "Asia/Calcutta"));
}
public static OffsetDateTime getOffsetDateTimeWithZoneId(OffsetDateTime odt, String zoneId) {
return odt.withOffsetSameInstant(getOffset(zoneId));
}
public static ZoneOffset getOffset(String zoneId) {
return ZonedDateTime.now(ZoneId.of(zoneId)).getOffset();
}
}
Output:
2020-12-28T20:08:25.026349Z
2020-12-28T20:08:25.026349Z
2020-12-28T22:08:25.026349+02:00
2020-12-28T14:08:25.026349-06:00
2020-12-29T01:38:25.026349+05:30
Using the legacy API:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
public class Main {
public static void main(String... args) throws ParseException {
// Test
Date date = Calendar.getInstance().getTime();
System.out.println(date);
System.out.println(getFormattedDateTimeWithZoneId(date, "Europe/London"));
System.out.println(getFormattedTimeWithZoneId(date, "Europe/London"));
System.out.println(getFormattedDateTimeWithZoneId(date, "Africa/Johannesburg"));
System.out.println(getFormattedTimeWithZoneId(date, "Africa/Johannesburg"));
System.out.println(getFormattedDateTimeWithZoneId(date, "America/Chicago"));
System.out.println(getFormattedTimeWithZoneId(date, "America/Chicago"));
System.out.println(getFormattedDateTimeWithZoneId(date, "Asia/Calcutta"));
System.out.println(getFormattedTimeWithZoneId(date, "Asia/Calcutta"));
}
public static String getFormattedDateTimeWithZoneId(Date date, String zoneId) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss a zzz", Locale.ENGLISH);
sdf.setTimeZone(TimeZone.getTimeZone(getOffset(zoneId)));
return sdf.format(date);
}
public static String getFormattedTimeWithZoneId(Date date, String zoneId) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss a", Locale.ENGLISH);
sdf.setTimeZone(TimeZone.getTimeZone(getOffset(zoneId)));
return sdf.format(date);
}
public static String getOffset(String zoneId) {
int offset = TimeZone.getTimeZone(zoneId).getRawOffset();// milliseconds to be added to UTC
int seconds = offset / 1000;
int hours = seconds / 3600;
int minutes = (seconds % 3600) / 60;
return "GMT" + (offset >= 0 ? "+" : "-") + String.format("%02d", Math.abs(hours)) + ":"
+ String.format("%02d", minutes);
}
}
Output:
Mon Dec 28 20:47:25 GMT 2020
2020-12-28 08:47:25 PM GMT+00:00
08:47:25 PM
2020-12-28 10:47:25 PM GMT+02:00
10:47:25 PM
2020-12-28 02:47:25 PM GMT-06:00
02:47:25 PM
2020-12-29 02:17:25 AM GMT+05:30
02:17:25 AM
Learn about the modern date-time API from Trail: Date Time.
java.time
Consider using java.time, the modern Java date and time API, for your time work. In particular when it’s non-trivial as yours is.
To get the current time in LA:
LocalTime timeInLa = LocalTime.now(ZoneId.of("America/Los_Angeles"));
System.out.println("Current time in LA: " + timeInLa);
Output when I ran just now:
Current time in LA: 11:10:18.975
For other cities supply the corresponfing time zone ID, for example Europe/London or Asia/Dubai. The ID for Brasilia is America/Sao_Paulo. I suggest that you build a map from city name to time zone ID so you can get the ID in a matter of a map lookup and won’t need the long switch statement.
Once we’ve got a LocalTime object, we can take out the hour of day.
int hourOfDayInLa = timeInLa.getHour();
System.out.println("Hour of day in LA: " + hourOfDayInLa);
Hour of day in LA: 11
Whehter you need to make any adjustments to this value, and which, to have your time picker display the time right — I would certainly not expect so, but it’s not something I know nor can tell you.
What I can tell you is that we can also get the clock hour of AM or PM and either 0 for AM or 1 for PM from the LocalTime object:
int clockHourOfAmOrPm = timeInLa.get(ChronoField.CLOCK_HOUR_OF_AMPM);
int amOrPmIndexInLa = timeInLa.get(ChronoField.AMPM_OF_DAY);
String amPm = amOrPmIndexInLa == 0 ? "AM" : "PM";
System.out.format("Clock hour %d (1 through 12) %s (code %d)%n",
clockHourOfAmOrPm, amPm, amOrPmIndexInLa);
Clock hour 11 (1 through 12) AM (code 0)
(If the end goal was a string AM or PM, we should use a formatter for that: I was thinking that if you wanted to do further processing based on whether it was AM or PM, an int value of 0 or 1 would be more practical for that.)
Question: Doesn’t java.time require Android API level 26?
java.time works nicely on both older and newer Android devices. It just requires at least Java 6.
In Java 8 and later and on newer Android devices (from API level 26) the modern API comes built-in.
In non-Android Java 6 and 7 get the ThreeTen Backport, the backport of the modern classes (ThreeTen for JSR 310; see the links at the bottom).
On older Android either use desugaring or the Android edition of ThreeTen Backport. It’s called ThreeTenABP. In the latter case make sure you import the date and time classes from org.threeten.bp with subpackages.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Java Specification Request (JSR) 310, where java.time was first described.
ThreeTen Backport project, the backport of java.time to Java 6 and 7 (ThreeTen for JSR-310).
Java 8+ APIs available through desugaring
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.

how can you combine date and sql time into a single date time in java? [duplicate]

This question already has answers here:
How to merge java.sql.Date and java.sql.Time to java.util.Date?
(3 answers)
Merge java.util.date with java.sql.Time
(7 answers)
Closed 2 years ago.
Using java Calendar how can you combine the start date, day and starttime?
For example:
If the start date is 9/8/2020. The day is 2 and the start time is 8:00 AM then how can we obtain a java date that is 9/9/2020 8:00 AM. Here is my unsuccessful attempt.
def startDateTime(Date startDate, int day, java.sql.Time startTime){
def date
date = Calendar.getInstance()
date.setTime(startDate)
//adding day. since day 1 is the first day we need to add day - 1
date.add(Calendar.DATE, day - 1)
// setting the time from startTime
date.setTimeInMillis(startTime.getTime())
return date.getTime()
}
Thanks for the help.
You are calling date.setTime(startDate) and date.setTimeInMillis(startTime.getTime()). 2nd method is overriding the time set in 1st method. You should create 2 separate instances of Calendar.
Here is how you can achieve this
Create separate Calendar instances for startDay and startTime
Construct a new Calendar object from separate Calendar objects created in #1 & add day as per requirement
Here is the complete code:
import java.sql.Time;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Calendar;
import java.util.Date;
public class ProofOfConcept {
public static void main(String[] args) {
int day = 2;
Time startTime = new Time(1, 1, 1);
Calendar timeCalendar = Calendar.getInstance();
timeCalendar.setTime(startTime);
Date startDate = new Date();
Calendar startDateCalendar = Calendar.getInstance();
startDateCalendar.setTime(startDate);
/* Only java 8 and above
LocalDateTime localDateTime = LocalDateTime.of(startDateCalendar.get(Calendar.YEAR), startDateCalendar.get(Calendar.MONTH) + 1, startDateCalendar.get(Calendar.DAY_OF_MONTH),
timeCalendar.get(Calendar.HOUR), timeCalendar.get(Calendar.MINUTE), timeCalendar.get(Calendar.SECOND));
localDateTime = localDateTime.plusDays(day);
System.out.println("localDateTime : " + localDateTime);
Date dateFromLocalDateTime = Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
System.out.println("dateFromLocalDateTime : " + dateFromLocalDateTime);*/
Calendar result = Calendar.getInstance();
result.set(startDateCalendar.get(Calendar.YEAR), startDateCalendar.get(Calendar.MONTH), startDateCalendar.get(Calendar.DAY_OF_MONTH) + 2,
timeCalendar.get(Calendar.HOUR), timeCalendar.get(Calendar.MINUTE), timeCalendar.get(Calendar.SECOND));
Date date = result.getTime();
System.out.println("date : " + date);
}
}
Output:
date : Tue Sep 08 01:01:01 IST 2020
Note : I suggest using java.time.* packages over java.util.*. Why? Check this. But this is only available in java 8. (Though, you can use joda time in versions below 8).
Edit : Moving Ole V.V. 's comment to answer.
For Java 7, I suggest using java.time, the modern Java date and time API, through the backport, ThreeTen Backport.
static LocalDateTime startDateTime(Date startDate, int day, java.sql.Time startTime) {
LocalTime startLocalTime = DateTimeUtils.toLocalTime(startTime);
return DateTimeUtils.toInstant(startDate)
.atZone(ZoneId.systemDefault())
.toLocalDate()
.plusDays(day - 1)
.atTime(startLocalTime);
}

Generating all days between 2 given dates in Java [duplicate]

This question already has answers here:
how to get a list of dates between two dates in java
(23 answers)
Closed 6 years ago.
I'm trying to get an array of Dates, while my input is a 'from'/'to' structure.
So my input is:
String date1 = "2014-01-01";
String date2 = "2014-05-01";
My output should be an Arraylist with all dates between date1 and date2.
I've already looked for this, but I could only find questions about the difference between 2 dates:
SimpleDateFormat myFormat = new SimpleDateFormat("dd MM yyyy");
String inputString1 = "23 01 1997";
String inputString2 = "27 04 1997";
try {
Date date1 = myFormat.parse(inputString1);
Date date2 = myFormat.parse(inputString2);
long diff = date2.getTime() - date1.getTime();
System.out.println ("Days: " + TimeUnit.DAYS.convert(diff,TimeUnit.MILLISECONDS));
} catch (ParseException e) {
e.printStackTrace();
}
Any hints or suggestions? All other questions are for iOS or SQL.
Take a look at JodaTime: http://joda-time.sourceforge.net/apidocs/org/joda/time/DateTime.html
DateTime dateTime1 = new DateTime(date1);
DateTime dateTime2 = new DateTime(date2);
List<Date> allDates = new ArrayList();
while( dateTime1.before(dateTime2) ){
allDates.add( dateTime1.toDate() );
dateTime1 = dateTime1.plusDays(1);
}
Below is the code to get array of dates between the two string date.
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
public class DateFormatExample {
public static void main(String[] args) {
// TODO Auto-generated method stub
SimpleDateFormat myFormat = new SimpleDateFormat("yyyy-MM-dd");
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
String date1 = "2014-01-01";
String date2 = "2014-05-01";
try {
Date d1 = myFormat.parse(date1);
Date d2 = myFormat.parse(date2);
List<Date> allDates = new ArrayList<Date>();
List<String> allDatesString = new ArrayList<String>();
while( d1.before(d2) ){
d1 = addDays(d1, 1);
allDates.add(d1);
allDatesString.add(formatter.format(d1));
}
System.out.println(allDates);
System.out.println(allDatesString);
} catch (ParseException e) {
e.printStackTrace();
}
}
private static Date addDays(Date d1, int i) {
GregorianCalendar cal = new GregorianCalendar();
cal.setTime(d1);
cal.add(Calendar.DATE, 1);
return cal.getTime();
}
}
If you don't want to use third party libraries you can use Calendar:
Check here a working demo.
public static void main(String[] args) throws Exception {
SimpleDateFormat myFormat = new SimpleDateFormat("dd MM yyyy");
String inputString1 = "23 01 1997";
String inputString2 = "27 04 1997";
ArrayList<Date> dates = new ArrayList<Date>();
try {
Date date1 = myFormat.parse(inputString1);
Calendar c1 = DateToCalendar(date1);
Date date2 = myFormat.parse(inputString2);
Calendar c2 = DateToCalendar(date2);
while (!areEqualDate(c1, c2)) {
dates.add(c1.getTime());
System.out.println (c1.getTime());
c1.add(Calendar.DAY_OF_YEAR, 1);
}
} catch (ParseException e) {
e.printStackTrace();
}
// ArrayList<Date> dates >> contain all dates between both given days.
}
private static boolean areEqualDate(Calendar c1, Calendar c2) {
if (c1.get(Calendar.YEAR) != c2.get(Calendar.YEAR)) return false;
if (c1.get(Calendar.MONTH) != c2.get(Calendar.MONTH)) return false;
if (c1.get(Calendar.DAY_OF_YEAR) != c2.get(Calendar.DAY_OF_YEAR)) return false;
return true;
}
public static Calendar DateToCalendar(Date date) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
return cal;
}
I like JodaTime, but this can also be done without 3rd party libraries by using java.util.Calendar. Given a Calendar object, one can use its add method to increase certain fields of the date while honoring the calendar rules (like adding 1 day to the 31st of January gets you to the 1st of February, not to the 32nd of January).
First get the dates into one Calendar object each, in the correct chronological order so adding is going in the right direction later:
Calendar cStart = Calendar.getInstance(),
cStop = Calendar.getInstance();
if (date1.before(date2)) {
cStart.setTime(date1);
cStop.setTime(date2);
} else {
cStart.setTime(date2);
cStop.setTime(date1);
date1 and date2 are the parsed Date objects from your question, for simplicity's sake.
Next, loop over an "add 1 to day-of-year" instruction until this gets you beyond the stop date:
do {
System.out.println(pretty(cStart));
cStart.add(Calendar.DAY_OF_YEAR, 1);
} while (cStart.before(cStop));
And lastly print the stop date
System.out.println(pretty(cStop));
pretty() is just some mini method sending the calendar through a SDF, like the one you used for parsing the Strings in the first place.
This solution will print the date range, including the start and stop dates, and might need some tweaking around the edge cases (like date1==date2). Can be easily adapted to exclude the start and stop dates. Printing can be swapped for aggregation of course. To get a Date object from the calendar, use the getTime() method (returns a snapshot, not a live reference).
The documentation for the relevant (Gregorian)Calendar can be found here.
In case you are using Guava, there is a very elegant solution to this problem.
Guava has two neat classes, such as Range and ContiguousSet, which implement exactly what you need: first one operates on ranges of values, and second one - is able to convert a range to a set of discrete values.
Example of usage of both (together with JodaTime):
LocalDate start = LocalDate.parse("2015-01-01");
LocalDate end = LocalDate.parse("2019-02-01");
Range<LocalDate> range = Range.closed(start, end); //Creates a "closed" range, that is both dates are inclusive. There are also options like "openClosed", "closedOpen" and "open"
final Set<LocalDate> daySet = ContiguousSet.create(range, LocalDateDomain.INSTANCE); //Create a "virtual" set of days in given the range. "virtual" part means that if you create a set of 10 thousand years, it will not eat your memory at all
for (LocalDate day : daySet) {
//...operation...
}
Personally, I really prefer this way, as it eliminates some problems with understanding closed/open ranges, and makes code much easier to read and understand, while making no impact on performance. Also, it works with any kinds of dates, any libraries (you can swap YodaTime to Java8 Dates or even Java7- Date-based implementation).
Moreover, it allows you to do some neat operations on ranges like intersections, unions, spanning of ranges, incredibly fast "contains" and so on.
Only downsides are:
Dependence on Guava.
Need to create a special "DiscreteDomain" class, which Guava uses to understand where one date ends and other begins.
Example of LocalDateDomain implementation which operates as a bridge between Guava and JodaTime:
public class LocalDateDomain extends DiscreteDomain<LocalDate> {
public static final LocalDateDomain INSTANCE = new LocalDateDomain();
#Override
public LocalDate next(LocalDate value) {
return value.plusDays(1);
}
#Override
public LocalDate previous(LocalDate value) {
return value.minusDays(1);
}
#Override
public long distance(LocalDate start, LocalDate end) {
return Days.daysBetween(start, end).getDays();
}
}
I already know that OP isn't using Java 8 but here's the current solution - Java has been revamped and the new java.time API does every conceivable job in that regard:
//change these values :
LocalDate ld1 = LocalDate.ofEpochDay(0);
LocalDate ld2 = LocalDate.now();
//do NOT change these:
final LocalDate begin = ld1.isBefore(ld2) ? ld1 : ld2;
final LocalDate end = ld2.isAfter(ld1) ? ld2 : ld1;
for (int i = 0; i < begin.until(end, ChronoUnit.DAYS); i++) {
final LocalDate curDate = begin.plusDays(i);
System.out.println("current date : " + curDate);
}
This will output every valid day between the two dates whereas most of the other solutions will also give you invalid ones; heres the thing: temporal calculations need to be done on timezone-independent data - the output on the other hand may very well be timezone and/or chronology -dependent.
Thats why there are packages like java.time.format - simply calculate your time/date values and format them for your chosen region ... thats how its done correctly.
If you need to convert temporal input there are also useful functions in the time-API, i recommend doing a thorough tutorial on the subject, a few good introductions may be this and especially that :
There are two basic ways to represent time. One way represents time in
human terms, referred to as human time, such as year, month, day,
hour, minute and second. The other way, machine time, measures time
continuously along a timeline from an origin, called the epoch, in
nanosecond resolution. The Date-Time package provides a rich array of
classes for representing date and time. Some classes in the Date-Time
API are intended to represent machine time, and others are more suited
to representing human time.

Java Date is giving incorrect time difference, jumps 1 hour ahead

My time difference is showing an incorrect output, I'm trying to calculate the time difference between startTime and endTime.
Date time1, time2;
long difference;
SimpleDateFormat df = new SimpleDateFormat("HH:mm");
public Time(String startTime, String endTime)
{
this.startTime = startTime;
this.endTime = endTime;
time1 = new Time("16:30", "18:00"); //example
try
{
time1 = df.parse(startTime);
time2 = df.parse(endTime);
}
catch(Exception e) {
System.out.println("invalid time");
}
}
public String getDifference()
{
difference = (time2.getTime() - time1.getTime());
return df.format(difference); //output = 02:30, should be 01:30
}
I know that Joda-Time could make this easier, but I'm supposed not to use any other library.
It calculates the difference correctly as 5400000 milliseconds (1.5 hours), but formats it as 02:30, due to, I think, the time zone.
Add this line in your constructor to set the date format to the UTC time zone, and it should output 01:30 as you expect:
df.setTimeZone(java.util.TimeZone.getTimeZone("UTC"));
Time is the number of milliseconds since a moment called epoch. In your code, you calculate the difference between to moments, and then interpret the result as a timestamp, but it isn't.
The calculated result is the difference between two timestamps in milliseconds. If you want that printed in hours and minutes, do something like:
public String getDifference() {
difference = (time2.getTime() - time1.getTime()) / 1000L;
long hours = difference/3600;
difference %= 3600;
long minutes = difference/60;
difference %= 60;
long seconds = difference;
return String.format("%d:%02d:%02d", hours, minutes, seconds);
}
The date-time API of java.util and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern date-time API.
For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7.
If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.
Demo:
import java.time.Duration;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("H:m", Locale.ENGLISH);
LocalTime begin = LocalTime.parse("16:30", dtf);
LocalTime end = LocalTime.parse("18:00", dtf);
Duration duration = Duration.between(begin, end);
System.out.println(duration);
// Custom format
// ##########################################Java-8##########################################
System.out.println(String.format("%d:%d", duration.toHours(), duration.toMinutes() % 60));
// ##########################################################################################
// ##########################################Java-9##########################################
System.out.println(String.format("%d:%d", duration.toHoursPart(), duration.toMinutesPart()));
// ##########################################################################################
}
}
Output:
PT1H30M
1:30
1:30
Learn about the modern date-time API from Trail: Date Time.

How to check if time stamp (epoch time) is of today's or yesterday's [android]

I want to convert the time stamp (epoch time) to human readable string.
For that i am using calendar.setTimeInMillis(timeSinceEpoch) function to create the calender object and to get the date time string in human readable format.
I am confused on, How can I find out that the time stamp (epoch time) is of today or yesterday or it is in the same week as per the system's current date and time?
Is there any API's to achieve this in android?
Thanks.
You can use methods:
public static long diff(long time, int field) {
long fieldTime = getFieldInMillis(field);
Calendar cal = Calendar.getInstance();
long now = cal.getTimeInMillis();
return (time/fieldTime - now / fieldTime);
}
private static final long getFieldInMillis(int field) {
// TODO cache values
final Calendar cal = Calendar.getInstance();
long now = cal.getTimeInMillis();
cal.add(field, 1);
long after = cal.getTimeInMillis();
return after - now;
}
and use them this way:
diff(time, Calendar.DAY_OF_YEAR); // 0 - today, 1 - tomorrow, -1 - yesterday
diff(time, Calendar.WEEK_OF_YEAR); // 0 - this week, -1 - last week etc.
Its really simple:
Calendar c=Calendar.getInstance();
c.getTimeInMillis();
String cur_day=String.format("%te %B %tY",c,c,c); // This will give date like 22 February 2012
c.setTimeInMillis(time);//set your saved timestamp
String that_day=String.format("%te %B %tY",c,c,c); //this will convert timestamp into format like 22 February 2012
//you can compare days,months,year,hours,minutes,seconds and milliseconds using above method.you can find various formats in below link
For more formats,please refer http://download.oracle.com/javase/1.5.0/docs/api/java/util/Formatter.html
You can try to use this for detect today date:
public static boolean isDateToday(long milliSeconds) {
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(milliSeconds);
Date getDate = calendar.getTime();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
Date startDate = calendar.getTime();
return getDate.compareTo(startDate) > 0;
}
i think this is the most efficient way of figuring out if two timestamps are on the same day. plus it's language-independent:
int secondsInADay = 60*60*24;
int daysSinceEpoch1 = timestamp1/secondsInADay;
int daysSinceEpoch2 = timestamp2/secondsInADay;
if( daysSinceEpoch1 == daysSinceEpoch2 )
;//sameday
else if( daysSinceEpoch1 - daysSinceEpoch2 == 1 )
;//timestamp2 is a day before timetamp1
else if( ......
set timestamp1 to the current time if you want to compare to today
java.time
The legacy date-time API (java.util date-time types and their formatting type, SimpleDateFormat etc.) is outdated and error-prone. It is recommended to stop using it completely and switch to java.time, the modern date-time API*.
Solution using java.time, the modern API:
The modern date-time API is rich with intuitive concepts e.g. it provides us with the class, Instant which represents an instantaneous point on the timeline. There is a class called ZonedDateTime which represents a date-time with a time-zone in the ISO-8601 calendar system. In order to switch to a different time unit (e.g. day, hour, minute, week, month etc.), the API provides methods named as prepositions and other spoken English constructs. Learn more about the modern date-time API from Trail: Date Time.
The concepts like today, yesterday, same week etc. are bounds to a timezone e.g a moment today in London can be tomorrow in Singapore. Also, the start of the week is Locale-sensitive e.g. for Locale.France, it starts on Monday whereas for Locale.US, it starts on Sunday.
Demo:
import java.time.DayOfWeek;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.temporal.TemporalAdjusters;
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) {
// Test
Stream.of(
1621533017083L,
1621446617083L,
1621619417083L,
1621189684296L,
1621209600000L,
1621814400000L
).forEach(millis -> {
System.out.println(millis);
System.out.println(Instant.ofEpochMilli(millis));
System.out.println("Today: " + isToday(millis, "Europe/London"));
System.out.println("Yesterday: " + isYesterday(millis, "Europe/London"));
System.out.println("In the current week: " + isInTheSameWeek(millis, "Europe/London"));
System.out.println();
});
}
static boolean isToday(long epochMillis, String timezone) {
ZoneId zoneId = ZoneId.of(timezone);
// The start of the day today at this timezone
ZonedDateTime zdtStartOfDayToday = LocalDate.now().atStartOfDay(zoneId);
long millisStartOfDayToday = zdtStartOfDayToday.toInstant().toEpochMilli();
// The start of the next day at this timezone
ZonedDateTime zdtStartOfDayNextDay = LocalDate.now().plusDays(1).atStartOfDay(zoneId);
long millisStartOfDayNextDay = zdtStartOfDayNextDay.toInstant().toEpochMilli();
return (epochMillis >= millisStartOfDayToday && epochMillis < millisStartOfDayNextDay);
}
static boolean isYesterday(long epochMillis, String timezone) {
ZoneId zoneId = ZoneId.of(timezone);
// The start of the day today at this timezone
ZonedDateTime zdtStartOfDayToday = LocalDate.now().atStartOfDay(zoneId);
long millisStartOfDayToday = zdtStartOfDayToday.toInstant().toEpochMilli();
// The start of the day yesterday at this timezone
ZonedDateTime zdtStartOfDayYesterday = LocalDate.now().minusDays(1).atStartOfDay(zoneId);
long millisStartOfDayYesterday = zdtStartOfDayYesterday.toInstant().toEpochMilli();
return (epochMillis >= millisStartOfDayYesterday && epochMillis < millisStartOfDayToday);
}
static boolean isInTheSameWeek(long epochMillis, String timezone) {
ZoneId zoneId = ZoneId.of(timezone);
// The start of the day today at this timezone
ZonedDateTime zdtStartOfDayToday = LocalDate.now().atStartOfDay(zoneId);
// The start of the week at this timezone
ZonedDateTime zdtStartOfTheWeek = zdtStartOfDayToday.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
long millisStartOfTheWeek = zdtStartOfTheWeek.toInstant().toEpochMilli();
// The start of the next week at this timezone
ZonedDateTime zdtStartOfTheNextWeek = zdtStartOfDayToday.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
long millisStartOfTheNextWeek = zdtStartOfTheNextWeek.toInstant().toEpochMilli();
return (epochMillis >= millisStartOfTheWeek && epochMillis < millisStartOfTheNextWeek);
}
}
Output:
1621533017083
2021-05-20T17:50:17.083Z
Today: true
Yesterday: false
In the current week: true
1621446617083
2021-05-19T17:50:17.083Z
Today: false
Yesterday: true
In the current week: true
1621619417083
2021-05-21T17:50:17.083Z
Today: false
Yesterday: false
In the current week: true
1621189684296
2021-05-16T18:28:04.296Z
Today: false
Yesterday: false
In the current week: false
1621209600000
2021-05-17T00:00:00Z
Today: false
Yesterday: false
In the current week: true
1621814400000
2021-05-24T00:00:00Z
Today: false
Yesterday: false
In the current week: false
ONLINE DEMO
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.
time should be in milli seconds
DateUtils.isToday(time)

Categories

Resources