What is the Android equivalent of iPhone's NSCalendar? - java

What might be the Android equivalent of the following iPhone code?
NSCalendar *calender = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];
int units = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit;
NSDateComponents *components = [calender components:units fromDate:[NSDate date] toDate:destinationDate options:0];
I am trying to do a date countdown to show the number of years, months, days, hours, minutes and seconds in a consecutive manner, not show the years, months, days, hours, minutes and seconds as a whole.
I have this, but I cannot get the hours, minutes and seconds. When I play with the hours, I keep getting hours in the days, not hours left.
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = null;
try {
date = format.parse(myDate);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
long nat = Math.round(date.getTime() / 1000);
long totaldifference = Math.abs(d1-d2);
long date_diff = Math.round(totaldifference/(24*3600));
//year
double year2 = Math.floor(date_diff/365);
date_diff-=year2*365;
double month2 = Math.floor(date_diff/30.5);
date_diff-=month2*30.5;
long day2 = date_diff;

To get a Calendar, you can do this:
Calendar cal = Calendar.getInstance()
Doing it this way will initialize it to the current date and time. Check the documentation if you need to set it to a different date or time.
To get the year, month, day, and so on, you can do this:
int year = cal.get(Calendar.YEAR)
int month = cal.get(Calendar.MONTH)
int day = cal.get(Calendar.DATE)
To "count down" on that, you can add a negative of whatever unit you want to count down in:
cal.add(Calendar.SECOND, -1)

Have a look at the documentation for calendar it should help. You get the year, month, day etc all seperately so should be easy to implement your countdown. Its a base class so you should be able to extend it to do what you need.

Related

What is the algorithm represented in Java to convert an 12 hour am/pm meridiem format hour to 24 hour format?

I needed to convert only the hour part of 12 hour time string to 24 hour format. I'm not interested in other than hour parts of a date string. SimpleDateFormatter is notoriously buggy and I in fact I'm more interested in the conversion algorithm itself. So what I want is to find the algorithm to convert the hour part. This is example of an uncleaned string containing hour part: "12:15PM". Sometimes there is spaces between minutes and meridiem sometimes not. Sometimes it has also character 160. So before conversion method I check and clean the string parts and then feed then meridiem(am or pm) and hour to the method which returns hour as 24 hour format int.
This is my naive style code for beginners to convert an hour in 12 hour format to an hour in 24 format.
public static int convert12to24(String meridiem, String hour) {
//meridiem is that am or pm,
meridiem = meridiem.toLowerCase();
int h_12 = 0;
int h_24 = 0;
try {
h_12 = Integer.parseInt(hour);
} catch (NumberFormatException e) {
e.printStackTrace();
}
if (h_12 == 12) {
//this is the midnight hour
if (meridiem.contains("am")) {//generally before noon
h_24 = 0;
} else {//this is the hour starting at noon
h_24 = 12;
}
} else if (h_12 >= 1)//all the rest
{
if (meridiem.contains("am")) {
//hour starting after first hour at midnight to 11 facing noon
h_24 = h_12;
} else {//pm hours starting right after first hour after noon
h_24 = h_12 + 12;
}
}
return h_24;
}
java.time
I recommend using java.time, the modern Java date and time API, rather than your own calendar implementation. It can be used in all locales.
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("h:mma", Locale.ENGLISH);
String timeString12Hours = "12:15PM";
LocalTime time = LocalTime.parse(timeString12Hours, formatter);
System.out.println("Time: " + time);
int hour = time.getHour();
System.out.println("Hour of day in 24 hour format: " + hour);
Output is:
Time: 12:15
Hour of day in 24 hour format: 12
What we get for free from java.time is validation. This code will detect if meridiem is not either AM or PM, or the hour is outside the range 1 through 12 or not a number at all.
Under no circumstances use the SimpleDateFormat class mentioned in the question. It’s a notorious troublemaker of a class and long outdated.
Edit: If for compatibility with old code that I don’t know and that you haven’t got time to clean up at the moment you need the method signature from your own answer:
private static DateTimeFormatter meridiemHourFormatter
= DateTimeFormatter.ofPattern("ahh", Locale.ENGLISH);
public static int convert12to24(String meridiem, String hour) {
String meridiemHour = meridiem + hour;
return LocalTime.parse(meridiemHour, meridiemHourFormatter).getHour();
}
Trying it out:
System.out.println(convert12to24("PM", "12"));
12
Every reader can decide for himself or herself: Which method implementation takes less energy to understand if in a hurry, yours or mine?
Link: Oracle tutorial: Date Time explaining how to use java.time.

Checking dates if it is in a range

My Java FX app handles hours worked. I have work start and end time in 2 date fields. I succeeded in calculating the differences between 2 datesTime; but now how could I check if the result is in a night or day range???? The day begin at 6 and ends at 22h. For example someone who worked between 3Am till 11Pm.
Here is below how I did to have the total number of hours worked.
public void CalculNbreJourTravaille() {
SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyy HH:mm");
try {
Date ddtt = format.parse(ddt.getText());
Date dftt = format.parse(dft.getText());
long diff = dftt.getTime() - ddtt.getTime();
long diffhours = diff / (60*60*1000)%24;
long diffdays = diff/(24*60*60*1000);
long total = diffhours + (diffdays*24);
result.setText(total + " Hours");
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
We have workers who can work beyond 10PM, and the pay would not be the same. If they work after 10pm, they will have a special pay. We pay at the end of the work. They could would work only 10 days or more.
You should use the new DateTimeFormatter class to give you a LocalDateTime object, which you can pull the hour from.
DateTimeFormatter format = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm");
LocalDateTime localDateTimeFrom = format.parse(dateFrom.getText(), LocalDateTime::from);
LocalDateTime localDateTimeTo = format.parse(dateTo.getText(), LocalDateTime::from);
int hoursFrom = localDateTimeFrom.getHour();
int hoursTo = localDateTimeTo.getHour();
boolean workedNight = hoursFrom < 6 || hoursTo > 22;
Here’s my attempt to cover all of your requirements. I wrote the code before reading that you don’t require that summer time (DST) is taken into account, so I am using ZonedDateTime to get correct hours also across summer time transitions. For the same reason I need to iterate over each day. For each date I calculate the hours worked at night time and the hours worked at day time.
If you want to make sure that summer time is not taken into account, use LocalDateTime instead of ZonedDateTime. In this case there may also be a possible performance gain in calculating the whole work days in one lump rather than one day at a time.
The code below uses 28/03/2018 03:00 and 29/03/2018 23:30 as example start and end time. Expected total hours worked are 44.5 since one day is 24 hours and there are 20.5 hours from 03:00 to 23:30. The expected day time hours are 32 since there are 16 daytime hours each of the two days. This leaves 12.5 hours as night time. And indeed the code prints
Day 32.0 hours; night 12.5 hours
The program follows. Please fill in the correct time zone where I put America/Monterey.
static ZoneId zone = ZoneId.of("America/Monterrey");
static LocalTime dayStart = LocalTime.of(6, 0);
static LocalTime dayEnd = LocalTime.of(22, 0);
static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d/M/uuuu H:mm");
public static void main(String[] args) {
String workStartString = "28/03/2018 03:00";
String workEndString = "29/03/2018 23:30";
calculateWorkingHours(workStartString, workEndString);
}
public static void calculateWorkingHours(String workStartString, String workEndString) {
ZonedDateTime workStart
= LocalDateTime.parse(workStartString, formatter).atZone(zone);
ZonedDateTime workEnd
= LocalDateTime.parse(workEndString, formatter).atZone(zone);
if (workEnd.isBefore(workStart)) {
throw new IllegalArgumentException("Work end must not be before work start");
}
LocalDate workStartDate = workStart.toLocalDate();
LocalDate workEndDate = workEnd.toLocalDate();
Duration workedDaytime = Duration.ZERO;
// first calculate work at nighttime before the start date, that is, work before 06:00
Duration workedNighttime
= calculateNightTime(workStartDate.minusDays(1), workStart, workEnd);
for (LocalDate d = workStartDate; ! d.isAfter(workEndDate); d = d.plusDays(1)) {
workedDaytime = workedDaytime.plus(calculateDayTime(d, workStart, workEnd));
workedNighttime = workedNighttime.plus(calculateNightTime(d, workStart, workEnd));
}
double dayHours = workedDaytime.toMinutes() / (double) TimeUnit.HOURS.toMinutes(1);
double nightHours = workedNighttime.toMinutes() / (double) TimeUnit.HOURS.toMinutes(1);
System.out.println("Day " + dayHours + " hours; night " + nightHours + " hours");
}
/**
* Calculates amount of work in daytime on d,
* that is between 06:00 and 22:00 on d.
* Only time that falls with in workStart to workAnd
* and also falls within 06:00 to 22:00 on d is included.
*
* #param d The date for which to calculate day work
* #param workStart
* #param workEnd
* #return Amount of daytime work on the said day
*/
private static Duration calculateDayTime(LocalDate d, ZonedDateTime workStart, ZonedDateTime workEnd) {
ZonedDateTime dayStartToday = d.atTime(dayStart).atZone(zone);
ZonedDateTime dayEndToday = d.atTime(dayEnd).atZone(zone);
if (workStart.isAfter(dayEndToday) || workEnd.isBefore(dayStartToday)) {
return Duration.ZERO;
}
// restrict calculation to daytime on d
if (workStart.isBefore(dayStartToday)) {
workStart = dayStartToday;
}
if (workEnd.isAfter(dayEndToday)) {
workEnd = dayEndToday;
}
return Duration.between(workStart, workEnd);
}
/**
* Calculates amount of night work in the night after d,
* that is from 22:00 on d until 06:00 the next morning.
*
* #param d The date for which to calculate night work
* #param workStart
* #param workEnd
* #return Amount of nighttime work in said night
*/
private static Duration calculateNightTime(LocalDate d, ZonedDateTime workStart, ZonedDateTime workEnd) {
assert ! workEnd.isBefore(workStart);
ZonedDateTime nightStart = d.atTime(dayEnd).atZone(zone);
ZonedDateTime nightEnd = d.plusDays(1).atTime(dayStart).atZone(zone);
if (workEnd.isBefore(nightStart) || workStart.isAfter(nightEnd)) {
return Duration.ZERO;
}
// restrict calculation to the night after d
if (workStart.isBefore(nightStart)) {
workStart = nightStart;
}
if (workEnd.isAfter(nightEnd)) {
workEnd = nightEnd;
}
return Duration.between(workStart, workEnd);
}
You can check the LocalTime part of a LocalDateTime to have a simple check using isAfter and isBefore.
I will use those values for this example.
LocalDateTime start = LocalDateTime.of(2018, Month.APRIL, 30, 23, 0);
LocalDateTime end = LocalDateTime.of(2018, Month.MAY, 1, 5, 0);
Then define the limit for the night.
LocalTime startNight = LocalTime.of(22, 0);
LocalTime endNight = LocalTime.of(6, 0);
And simply use get the LocalTime of both date and check if they are in the range. You can get the value using toLocalTime.
if(start.toLocalTime().isAfter(startNight) &&
end.toLocalTime().isBefore(endNight)){
System.out.println("NIGHT TIME");
} else {
System.out.println("DAY TIME");
}
NIGHT TIME
The output is valid since we start at 23:00 and end at 05:00.
Using this allow a simpler solution if you need to define a time like LocalTime.of(5,45) for 5:45
This is an example, this might need some adaptation if it is allowed to start part 22 but keep working after 6. This is just an example on how to use those methods.
This is easier, if you use the java.time API. You simply need to check, if the dates differ or if the starting time not in the range from 6:00 to 22:00:
private static final LocalTime START_TIME = LocalTime.of(6, 0); // 06:00
private static final LocalTime END_TIME = LocalTime.of(22, 0); // 22:00
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm");
// parse from input strings
LocalDateTime start = LocalDateTime.parse(startText, FORMATTER);
LocalDateTime end = LocalDateTime.parse(endText, FORMATTER);
boolean nightTime =
!start.toLocalDate().equals(end.toLocalDate())
|| start.toLocalTime().isBefore(START_TIME)
|| end.toLocalTime().isAfter(END_TIME);
// todo: change output to gui
System.out.println("night time: " + nightTime);
System.out.println("duration : " + Duration.between(start, end).toHours());
Define two formatters. One Fromatter to get date with time from edittext. And other On to get 12AM of that day. Now we need Date Objects corresponding to 6AM and 11PM of the same day. We can get those by adding that much milliseconds to the 12AM Object. These added dates can be used for comparison.
SimpleDateFormat df_zero_hours = new SimpleDateFormat("dd/MM/yyy");
SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm");
Date ddtt = format.parse(ddt.getText()); //Work Start Time
Date dftt = format.parse(dft.getText()); //Work End Time
Date dateStart = df_zero_hours.parse(ddt.getText()); //12AM of the day job started
Date dayStart = new Date();
dayStart.setTime(dateStart.getTime()+6*60*60*1000); // Get 6AM of that day
Date dayEnd = new Date();
dayEnd.setTime(dateStart.getTime()+22*60*60*1000); //Get 10PM of that day
// Now check the worked hours. in Whatever way you need
boolean isBefore6AM = (dayStart.getTime()-ddtt.getTime())>0;
boolean isAfter10PM = (dftt.getTime()-dayEnd.getTime())>0;

How to calculate remaining days?

private long calculateRemainingDays() {
final Calendar c = Calendar.getInstance();
c.set(2015, 7, 23);
final Calendar today = Calendar.getInstance();
final long millis = c.getTimeInMillis()
- today.getTimeInMillis();
// Convert to days
final long days = millis / 86400000;
return days;
}
I need to add a function in my android application. I want a remaining days from current day to 2015/9/30. When the date is change to next day, the remaining days will decrease. I would like to say like that:
7 days remaining... 6/5/4/etc... Please help me to get correct remaining days. Sorry for my poor english. Thanks!
Use Calender.JULY instead of 7 in the parameters for the set() method.
7 = August.
6 = July.
As it starts with January as 0. It's better to use the static instance variables like Calender.JANUARY.
But as you want to calculate till 2015/9/30, you should set the value as
c.set(2015, Calender.SEPTEMBER, 09);
The rest of the code seems ok. It will return the correct number of days.
Try this :-
final long millis = c.getTimeInMillis()
- today.getTimeInMillis();
System.out.println ("Days: " + TimeUnit.DAYS.convert(millis , TimeUnit.MILLISECONDS));
if you don't mind using joda.time
you can do something of this form:
final Calendar c = Calendar.getInstance();
c.set(2015, Calender.SEPTEMBER, 30);
Date endDate = c.getTime();
Instant startInstant = new Instant(new Date());
Instant endInstant = new Instant(endDate);
Days days = Days.daysBetween(startInstant, endInstant);

Display and save only hours in int

How to display only hours and using int variable? I mean print time like 20:30:44 PM, I want to store only hours, mean 20 in int variable. how to do that?
Can anybody tell me the code if you know, thanks?
Try using Calendar's get method like:
Calendar c = ..
c.setTime(...);//if you have time in long coming from somewhere else
int hour = c.get(Calendar.HOUR_OF_DAY);
If you try to parse time from String I recommend these solutions:
String time = "20:30:44 PM"; // this is your input string
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss aa");
try {
Date date = sdf.parse(time);
// this is the uglier solution
System.out.println("The hour is: "+date.getHours());
GregorianCalendar gc = new GregorianCalendar();
gc.setTime(date);
// this is nicer solution
System.out.println("The hour is: "+gc.get(Calendar.HOUR_OF_DAY));
} catch (ParseException e) {
System.err.println("Couldn't parse string! "+e.getMessage());
}
date.getHours() and gc.get(Calendar.HOUR_OF_DAY) return int, in this example I printed it out without creating variable.
You can, of course, use regular expression to find out hour in your string but above solutions should do the trick. You can learn more about SimpleDateFormat and available patterns here. I hope I helped you a bit.
EDIT: In his comment autor noted, that date isn't static (like in String) but dynamic:
Calendar calendar = new GregorianCalendar();
int hour = calendar.get(Calendar.HOUR_OF_DAY);
System.out.println("The hour is: "+hour);
I hope this helps.

Problem with time format

I wrote the following code to get the time
public String getTime() {
final Calendar cld = Calendar.getInstance();
String time = cld.get(Calendar.HOUR) + ":" + (cld.get(Calendar.MINUTE));
try {
Date date = new SimpleDateFormat("HH:mm").parse(time);
time = new SimpleDateFormat("HH:mm").format(date);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return time;
}
This always give me time like
11:59
01:07
But I need in 24 hrs format like:
11:59
13:07
How to change the code.
Use HOUR_OF_DAY instead of HOUR.
Use Calendar.HOUR_OF_DAY instead.
Calendar.HOUR = Field number for get and set indicating the hour of the morning or afternoon. HOUR is used for the 12-hour clock. E.g., at 10:04:15.250 PM the HOUR is 10.
Calendar.HOUR_OF_DAY = Field number for get and set indicating the hour of the day. HOUR_OF_DAY is used for the 24-hour clock. E.g., at 10:04:15.250 PM the HOUR_OF_DAY is 22.
Here's the code:
Calendar cal = Calendar.getInstance();
int hour = cal.get(Calendar.HOUR_OF_DAY);
int minute = cal.get(Calendar.MINUTE);
String time = hour + ":" + minute;
HH:mm is correct. 01:07 is 1am and 13:07 is 1pm. Wait until 1pm and see or create a date object and test it.

Categories