Android - checking if time is between certain hours of the day - android

in my app I'm updating some stuff if the time is between certain hours of the day which the user choose. It works fine if the user chooses something like "07-21", but not with "21-07" which is over the night.
How I'm doing to check the time is I'm getting the current hour and converting it into milliseconds. Then I check if the current milli is between the chosen hours (those are also converted into milliseconds).
Like this:
if (currentMilli >= startHourMilli && currentMilli <= endHourMilli)
The problem: It doesn't work if the user chooses anything that is over midnight (19-08 for example).
I've tried a lot of stuff but I just can't figure out how to do this.
Any help is appreciated!

Do you increase the day of the year by 1 when you're passing midnight? Otherwise your
startHourMilli might be greater than endHourMilli and your if-clause will always be false.
The solution is to use the add-method of the Calendar class. Therefore I calculate the interval's length in hours and add this value to our Calendar instance.
int start = 21; // let's take your failing example: 21-07
int end = 7;
int hours = (end - start) % 24; // here hours will be 14
Calendar cal = Calendar.getInstance();
// set calendar to TODAY 21:00:00.000
cal.set(Calendar.HOUR_OF_DAY, start);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
long startHourMilli = cal.getTimeInMillis();
// add 14 hours = TOMORROW 07:00:00.000
cal.add(Calendar.HOUR_OF_DAY, hours);
long endHourMilli = cal.getTimeInMillis();
Let me know if this helps :)

Simplest way to check..
val isDayTime : Boolean
get() {
val cal = Calendar.getInstance()
val hour = cal.get(Calendar.HOUR_OF_DAY)
return hour in 8..20
}

Date has the functions before and after for comparing two dates.
Hope this documentation helps you:
http://developer.android.com/reference/java/util/Date.html#after(java.util.Date)
http://developer.android.com/reference/java/util/Date.html#before(java.util.Date)
Best regards.

I'm answering my own question because I think I came up with something that might work for what I'm trying to do:
if(endHourMilli < startHourMilli){
if(currentMilli >= startHourMilli && currentMilli <= 23*3600000 || currentMilli >= 0 && currentMilli <= endHourMilli){
//Do whatever
}
}else{
if (currentMilli >= startHourMilli && currentMilli <= endHourMilli) {
//Do whatever
}
}
It should work even if endMilli is less than startMilli, or have I screwed something up here?

I know I'm a little late to the party, but recently I developed android app that needed to work within given timeframe, and since I didn't like working with Calendar I ended up using something like this:
// if start hour is later than end hour
// example: start = 21, end = 07
int startHourMilli = 21, endHourMilli = 07;
// just add one day (in your case in millis)
if (startHourMilli > endHourMilli) endHourMilli += 24 * 60 * 60 * 1000;
// now here you can check without any problems
if(currentMilli >= startHourMilli && currentMilli < endHourMilli){
// within timeframe, do stuff you need
} else {
// not in timeframe, find solution
}
Now I know that you found yourself a solution, but I think that my approach may be a little more understandable (at least to newbies that might get confused).

You can always use simple if / else for 24 hour format, without using functions or additional calculations:
For Example1: Full time period from StartHour to StopHour(stop hour include all minutes)
int StartHour = 23; //start from 23:00
int StopHour = 9; // until current hour is 9 that will include until 9:59
int CurrentHour = 2;
if (StartHour > StopHour)
{
if (CurrentHour < StartHour && StopHour < CurrentHour)
{Inside = false;}
else
{Inside = true;}
}
else
{
if (CurrentHour >= StartHour && StopHour >= CurrentHour)
{Inside = true;}
else
{Inside = false;}
}
At the end if Inside == true CurrentHour is in time range StartHour - StopHour(full stop hour)
And do something else if both equal:
if (StartHour == StopHour) {..............};
For Example2: If you want to stop at this exact StopHour hour, you need some changes:
int StartHour = 23; //start from 23:00
int StopHour = 9; // this will stop after 8:59
int CurrentHour = 2;
if (StartHour2 > StopHour2)
{
if (Hr24 < StartHour2 && StopHour2 <= Hr24)
{Quiet = false;}
else
{Quiet = true;}
}
else
{
if (Hr24 >= StartHour2 && StopHour2 > Hr24)
{Quiet = true;}
else
{Quiet = false;}
}
At the end if Inside == true CurrentHour is in time range StartHour - StopHour(exact)

I think that ottel142 is almost ok but it shoud be:
public static boolean checkIfNight() {
int start = 21;
int end = 7;
int hours = 24 - start + end;
Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR_OF_DAY, start);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
long startHourMilli = cal.getTimeInMillis();
KLog.e(cal.getTime());
cal.add(Calendar.HOUR_OF_DAY, hours);
long endHourMilli = cal.getTimeInMillis();
long currentMilli = Calendar.getInstance().getTimeInMillis();
if (currentMilli >= startHourMilli && currentMilli <= endHourMilli)
return true;
else return false;
}

Related

Android Calendar.getInstance() does not get today after midnight

I have the following code:
Calendar nextSchedule = Calendar.getInstance();
nextSchedule.set(Calendar.HOUR_OF_DAY, 0);
nextSchedule.set(Calendar.MINUTE, 0);
nextSchedule.set(Calendar.SECOND, 10);
nextSchedule.set(Calendar.MILLISECOND, 0);
nextSchedule.add(Calendar.DAY_OF_YEAR, 1);
Calendar cal = Calendar.getInstance();
long diff = nextSchedule.getTimeInMillis() - cal.getTimeInMillis();
long seconds = diff / 1000;
long minutes = seconds / 60;
long hours = minutes / 60;
As expected, around 11am it gave me 13/12hours but when doing the following in a widget:
Calendar nextSchedule = Calendar.getInstance();
nextSchedule.set(Calendar.HOUR_OF_DAY, 0);
nextSchedule.set(Calendar.MINUTE, 0);
nextSchedule.set(Calendar.SECOND, 10);
nextSchedule.set(Calendar.MILLISECOND, 0);
nextSchedule.add(Calendar.DAY_OF_YEAR, 1);
alarmManager.setExact(AlarmManager.RTC_WAKEUP, nextSchedule.getTimeInMillis(), pendingIntent);
Around 1:30am, it was still not updated. Only somewhen between 2am and 9am (I was asleep) it got updated.
A similar strange thing happens elsewhere. I have a calendar view (applandeo) with the following code: cvCalendar.setOnDayClickListener(eventDay -> showDateItems(eventDay,lvCalendar));
private void showDateItems(EventDay eventDay, ListView lvCalendar) {
Calendar cal = Calendar.getInstance();
Calendar cal2 = Calendar.getInstance();
cal.set(eventDay.getCalendar().get(Calendar.YEAR),eventDay.getCalendar().get(Calendar.MONTH),eventDay.getCalendar().get(Calendar.DATE));
cal2.set(eventDay.getCalendar().get(Calendar.YEAR),eventDay.getCalendar().get(Calendar.MONTH),1);
cal2.add(Calendar.MONTH, -1);
ArrayList<String> items = new ArrayList<>();
String line;
for (ItemsHistoryItem item: Utils.getInstance().itemsHistory) {
if (item.getxDay() < Utils.getInstance().calenderToEpoch(cal2) && item.getyDay() < Utils.getInstance().calenderToEpoch(cal2)) break;
if (item.getxDay() != Utils.getInstance().calenderToEpoch(cal) && item.getyDay() != Utils.getInstance().calenderToEpoch(cal)) continue;
line = item.getItemId() + ": $" + item.getAmount();
if (item.getxDay() == Utils.getInstance().calenderToEpoch(cal))
line += " (x day)";
else
line += " (y day)";
items.add(line);
}
ArrayAdapter<String> lcAdapter = new ArrayAdapter<>(requireActivity(), android.R.layout.simple_list_item_1, items);
lvCalendar.setAdapter(lcAdapter);
}
long calenderToEpoch(Calendar cal2) {
return TimeUnit.MILLISECONDS.toDays(cal2.getTimeInMillis());
}
Basically, the above code scans dates of items and when the user select a certain date, he gets a list of items which dates (x and y) are of that date. When doing so during the day, it works. When doing so in 1:30am (for example), it shifts one day ahead so if the user clicks on 12-oct, he gets the items of 11-oct. Somwhen between 2am and 9am it "shifts" back and works as expected.
Any idea what's wrong here?
I have a suggestion for using alarmmanager properly if you want it to fire exactly at the time you want else it does not fire on time when device is in deep sleep mode and gets delayed:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// use setAlarmClock function of AlarmManager
// but this function will show an alarm icon on statusbar
// if you dont want to show that icon you can use
// setExactAndAllowWhileIdle function but that will not be
// perfectly exact
}
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
// use setExact function of AlarmManager
}
else {
// use set function of AlarmManager
}
Apparently the default timezone for Calendar.getInstance() in my case was GMT+3 so at 3am the items were shown for their dates and the widget was updated. to fix it, I simply did the following:
Calendar cal = Calendar.getInstance();
cal.setTimeZone(TimeZone.getTimeZone("UTC"));

Error in adding recurrence event in Calendar

Hi I am tring to Create an app which add events to calendar. For example I need to create an event on every Saturday until dec 31ist.
The following are the attributes that I set for creating events,
event.put(CalendarContract.Events.CALENDAR_ID, 1);
event.put(CalendarContract.Events.TITLE, title);
event.put(CalendarContract.Events.DESCRIPTION, description);
event.put(CalendarContract.Events.EVENT_LOCATION, location);
event.put(CalendarContract.Events.DTSTART, sDate);
event.put(CalendarContract.Events.DURATION,"P50S");
event.put(CalendarContract.Events.ALL_DAY, 0);
event.put(CalendarContract.Events.HAS_ALARM, hasAlarm);
event.put(CalendarContract.Events.EVENT_TIMEZONE, timeZone);
event.put(CalendarContract.Events.RRULE, "FREQ=WEEKLY;BYDAY=SA;UNTIL=20151230");
mContext.getContentResolver().insert(baseUri, event);
But it create an event for the given date (sDate) and then create every Saturday. But how can I avoid that one event which created on given date (sDate)
I had the same problem. You need to check your reccurrence rule for day of week and offset your DTSTART to the nearest Saturday (or any other weekday that your recurrence rule contains). To give you rough example how to do that I'm attaching code from Android Calendar app that offsets start time and end time of the event based on reccurence rule string, and returns two long values - new start time and new end time if offset was applied, or null if it wasn't. EventRecurrence class can be found via search on GrepCode, its part of Android calendar app
public static long[] offsetStartTimeIfNecessary(long startMilis, long endMilis, String rrule) {
if (rrule == null || rrule.isEmpty() || rrule.replace("RRULE:", "").isEmpty()) {
// No need to waste any time with the parsing if the rule is empty.
return null;
}
long result[] = new long[2];
Calendar startTime = Calendar.getInstance();
startTime.setTimeInMillis(startMilis);
Calendar endTime = Calendar.getInstance();
endTime.setTimeInMillis(endMilis);
EventRecurrence mEventRecurrence = new EventRecurrence();
mEventRecurrence.parse(rrule.replace("RRULE:", ""));
// Check if we meet the specific special case. It has to:
// * be weekly
// * not recur on the same day of the week that the startTime falls on
// In this case, we'll need to push the start time to fall on the first day of the week
// that is part of the recurrence.
if (mEventRecurrence.freq != EventRecurrence.WEEKLY) {
// Not weekly so nothing to worry about.
return null;
}
if (mEventRecurrence.byday == null ||
mEventRecurrence.byday.length > mEventRecurrence.bydayCount) {
// This shouldn't happen, but just in case something is weird about the recurrence.
return null;
}
// Start to figure out what the nearest weekday is.
int closestWeekday = Integer.MAX_VALUE;
int weekstart = EventRecurrence.day2TimeDay(mEventRecurrence.wkst);
int startDay = startTime.get(Calendar.DAY_OF_WEEK) - 1;
for (int i = 0; i < mEventRecurrence.bydayCount; i++) {
int day = EventRecurrence.day2TimeDay(mEventRecurrence.byday[i]);
if (day == startDay) {
// Our start day is one of the recurring days, so we're good.
return null;
}
if (day < weekstart) {
// Let's not make any assumptions about what weekstart can be.
day += 7;
}
// We either want the earliest day that is later in the week than startDay ...
if (day > startDay && (day < closestWeekday || closestWeekday < startDay)) {
closestWeekday = day;
}
// ... or if there are no days later than startDay, we want the earliest day that is
// earlier in the week than startDay.
if (closestWeekday == Integer.MAX_VALUE || closestWeekday < startDay) {
// We haven't found a day that's later in the week than startDay yet.
if (day < closestWeekday) {
closestWeekday = day;
}
}
}
if (closestWeekday < startDay) {
closestWeekday += 7;
}
int daysOffset = closestWeekday - startDay;
startTime.add(Calendar.DAY_OF_MONTH, daysOffset);
endTime.add(Calendar.DAY_OF_MONTH, daysOffset);
result[0] = startTime.getTimeInMillis();
result[1] = endTime.getTimeInMillis();
return result;
}

queryUsageStats interval duration

I'm using UsageStatsManager API to get usage statistics for a certain time interval. All works fine if I use the predefined intervals i.e. INTERVAL_DAILY, INTERVAL_WEEKLY, INTERVAL_MONTHLY, INTERVAL_YEARLY. But if I want to view the data for the past 2 or 3 hours, I am getting today's data for the whole day. I have tried using Calendars and System.currentTimeMillis() but that didn't give me filtered results.
Calendar approach :
Calendar startCalendar = Calendar.getInstance();
startCalendar.add(Calendar.HOUR_OF_DAY, -2);
Calendar endCalendar = Calendar.getInstance();
And pass this to queryUsageStats method like this:
usageList = usm.queryUsageStats(interval, startCalendar.getTimeInMillis(), endCalendar.getTimeInMillis());
where interval is INTERVAL_BEST.
System.currentTimeMillis() approach :
long startTime = System.currentTimeMillis() - 7200*1000 // 7200 seconds i.e. 2 hrs
long endTime = System.currentTimeMillis();
Pass this to queryUsageStats just like above :
usageList = usm.queryUsageStats(interval, startTime, endTime);
where interval is again INTERVAL_BEST.
I'd like to know whether it's possible to get data for this duration i.e. less than a day, as the INTERVAL_BEST hasn't been documented properly to include this information. Any help would be appreciated as I'm stuck on this problem.
As UsageStatsManager doc says:
A request for data in the middle of a time interval will include that interval.
It seems that usage data is stored in buckets, and minimum bucket is a day, so you can't query usage stats for period less than a day. Even if you query a one-hour interval for a particular day, usage stats for the whole day is returned.
A little late to the party, but I think this might be useful to some.
You could use the queryEvents(long startTime, long endTime) from UsageStatsManager for achieving the desired result. The method could look like this (inspired by this post):
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public HashMap<String, AppUsageInfo> queryUsageStatistics(Context context, long startTime, long endTime) {
UsageEvents.Event currentEvent;
List<UsageEvents.Event> allEvents = new ArrayList<>();
HashMap<String, AppUsageInfo> map = new HashMap<>();
UsageStatsManager mUsageStatsManager = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);
assert mUsageStatsManager != null;
// Here we query the events from startTime till endTime.
UsageEvents usageEvents = mUsageStatsManager.queryEvents(startTime, endTime);
// go over all events.
while (usageEvents.hasNextEvent()) {
currentEvent = new UsageEvents.Event();
usageEvents.getNextEvent(currentEvent);
String packageName = currentEvent.getPackageName();
if (currentEvent.getEventType() == UsageEvents.Event.ACTIVITY_RESUMED || currentEvent.getEventType() == UsageEvents.Event.ACTIVITY_PAUSED ||
currentEvent.getEventType() == UsageEvents.Event.ACTIVITY_STOPPED) {
allEvents.add(currentEvent); // an extra event is found, add to all events list.
// taking it into a collection to access by package name
if (!map.containsKey(packageName)) {
map.put(packageName, new AppUsageInfo());
}
}
}
// iterate through all events.
for (int i = 0; i < allEvents.size() - 1; i++) {
UsageEvents.Event event0 = allEvents.get(i);
UsageEvents.Event event1 = allEvents.get(i + 1);
//for launchCount of apps in time range
if (!event0.getPackageName().equals(event1.getPackageName()) && event1.getEventType() == UsageEvents.Event.ACTIVITY_RESUMED) {
// if true, E1 (launch event of an app) app launched
Objects.requireNonNull(map.get(event1.getPackageName())).launchCount++;
}
//for UsageTime of apps in time range
if (event0.getEventType() == UsageEvents.Event.ACTIVITY_RESUMED &&
(event1.getEventType() == UsageEvents.Event.ACTIVITY_PAUSED || event1.getEventType() == UsageEvents.Event.ACTIVITY_STOPPED)
&& event0.getPackageName().equals(event1.getPackageName())) {
long diff = event1.getTimeStamp() - event0.getTimeStamp();
Objects.requireNonNull(map.get(event0.getPackageName())).timeInForeground += diff;
}
}
// and return the map.
return map;
}
The AppUsageInfo class would be:
public class AppUsageInfo {
public long timeInForeground;
public int launchCount;
AppUsageInfo() {
this.timeInForeground = 0;
this.launchCount = 0;
}
}
To then get the usage stats for the last two hours, simply call
Calendar startCalendar = Calendar.getInstance();
startCalendar.add(Calendar.HOUR_OF_DAY, -2);
Calendar endCalendar = Calendar.getInstance();
HashMap<String, AppUsageInfo> result = queryUsageStatistics(context, startCalendar.getTimeInMillis(), endCalendar.getTimeInMillis();

AlarmManager - How to set a Notification to appear annually

I want an notification to appear each year depending on the date entered (Birthday). I have everything else working bar how to set a notification annually. As you can see below I have changed the code to say "HERE" where the intervals go. There are intervals for days and I know I could multiply that by 365. But what happens if its a leap year..
int REQUEST_CODE = 7;
Intent intent = new Intent(Activity2.this, Receiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(Activity2.this, REQUEST_CODE, intent, 0);
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
am.setRepeating(am.RTC_WAKEUP, System.currentTimeMillis(), HERE, pendingIntent);
You could replace 'HERE' with a method that determines if the following February from today is in a leap year, and then returns the value 365 or 366 days (in the form of milliseconds mind you) based on those checks.
private long millisUntilNextYear(){
//Set days in a year for Leap and Regular
final int daysInLeapYear = 366;
final int daysInYear = 365;
//Get calendar instance
GregorianCalendar cal = (GregorianCalendar) GregorianCalendar.getInstance();
//Get this year and next year
int thisYear = cal.get(GregorianCalendar.YEAR);
int nextYear = thisYear + 1;
//Get today's month
int thisMonth = cal.get(GregorianCalendar.MONTH);
//Get today's date
int dayOfMonth = cal.get(GregorianCalendar.DAY_OF_MONTH);
//Is today before February? If so then the following February is in THIS year
if (thisMonth < GregorianCalendar.FEBRUARY){
//Check if THIS year is leapYear, and return correct days (converted to millis)
return cal.isLeapYear(thisYear) ? daysToMillis(daysInLeapYear) : daysToMillis(daysInYear);
}
//Is today after February? If so then the following February is NEXT year
else if (thisMonth > GregorianCalendar.FEBRUARY) {
//Check if NEXT year is leapYear, and return correct days (converted to millis)
return cal.isLeapYear(nextYear) ? daysToMillis(daysInLeapYear) : daysToMillis(daysInYear);
}
//Then today must be February.
else {
//Special case: today is February 29
if (dayOfMonth == 29){
return daysToMillis(daysInYear);
} else {
//Check if THIS year is leapYear, and return correct days (converted to millis)
return cal.isLeapYear(thisYear) ? daysToMillis(daysInLeapYear) : daysToMillis(daysInYear);
}
}
}
1) save dates in MM/DD/YY formats.
2) read these dates when you open your app(or at different times)
3) set alerts for single day/today it self.
Plus you can also show birthdays coming in next week/month etc.

How to get the amount of passed time till now from a given unix timestamp

I am given a unix timestamp and I need to find the difference of seconds/min/hour by comparing with current time. I need something like:
34 sec ago
1 min ago
4 mins ago
5 hours ago
1 days ago
2 days ago
I have tried some poor if-else styled code but it is giving wrong wierd output
String time = null;
long quantity = 0;
long addition = 0;
long diffMSec = System.currentTimeMillis() - Long.parseLong(submissionInfo
.get(CommonUtils.KEY_SUBMISSION_TIME)) * 1000L;
diffMSec /= 1000L;
if (diffMSec < 86400L) { // less than one day
if (diffMSec < 3600L) { // less than one hour
if (diffMSec < 60L) { // less than one minute
quantity = diffMSec;
time = "sec ago";
} else { // greater than or equal to one minute
addition = (diffMSec % 60L) > 0 ? 1 : 0;
quantity = (diffMSec / 60L) + addition;
if (quantity > 1)
time = "mins ago";
else
time = "min ago";
}
} else { // greater than or equal to one hour
addition = (diffMSec % 3600L) > 0 ? 1 : 0;
quantity = (diffMSec / 3600L) + addition;
if (quantity > 1)
time = "hours ago";
else
time = "hour ago";
}
} else { // greater than or equal to one day
addition = (diffMSec % 86400) > 0 ? 1 : 0;
quantity = (diffMSec / 86400) + addition;
if (quantity > 1)
time = "days ago";
else
time = "1 day ago";
}
time = quantity + " " + time;
I need some working code with smarter approach or even any approach with working solution. Help me to figure it out.
I think you should use Calendar
Calendar cal = Calendar.getInstance();
String time = "yourtimestamp";
long timestampLong = Long.parseLong(time)*1000;
Date d = new Date(timestampLong);
Calendar c = Calendar.getInstance();
c.setTime(d);
int year = c.get(Calendar.YEAR);
int month = c.get(Calendar.MONTH);
int date = c.get(Calendar.DATE);
Calendar implements Comparable so ...
long subs = Math.abs(cal.getTimeInMillis() c.getTimeInMillis());
Calendar subCalendar = (Calendar)cal.clone();
subCalendar.setTimeInMillis(subs);
You can also use this link, because it seems to be a problem like yours

Categories

Resources