I've been trying to get this to work for days and I'm tearing my hair out. I think I just need another pair of eyes to help me out.
I have "Entries" stored in a database, each with a Unix timestamp on the second they were entered. I have a system where the user can select any date and view the entries stored on the same week. The problem arises when I let the user set a custom first day of the week with Calendar.setFirstDayOfWeek(). I can never get a correct return value from the database with the first day of the week set to something other than Sunday (for this example, I'm using Tuesday).
public void getEntries() {
/* Make sure temp Calendar has same first day */
temp = Calendar.getInstance();
temp.setFirstDayOfWeek(date.getFirstDayOfWeek());
/* Common date ranges in unix time */
long oneday = 86400000L;
long oneweek = 604800000L;
long onemonth = 2628000000L;
long oneyear = 31536000000L;
/* The custom date in unix time. For example, the user may have selected Dec. 1, 2012 */
long set_time = date.getTimeInMillis();
entries.clear();
dba.open();
/* This query gets entries within 1 week and 1 day of the user-set date just to be safe */
Cursor cc = dba.query("Date < " +(set_time+oneweek+oneday)+ " AND Date > " +(set_time-oneday-oneweek));
if(cc.moveToFirst()) do {
/* Set temp calendar to the timestamp of the entry in database */
long unix = cc.getLong(1);
temp.setTimeInMillis(unix);
System.out.println("Temp calendar set to "+temp.getTime().toGMTString()+ " fdow("+temp.getFirstDayOfWeek()+") week("+temp.get(Calendar.WEEK_OF_YEAR)+"), user calendar set to "+date.getTime().toGMTString()+" fdow("+date.getFirstDayOfWeek()+") week("+date.get(Calendar.WEEK_OF_YEAR)+")");
if(temp.get(Calendar.WEEK_OF_YEAR) == date.get(Calendar.WEEK_OF_YEAR)
&& temp.get(Calendar.YEAR) == date.get(Calendar.YEAR) )
/* Entry object is instantiated and added to ArrayList if WEEK_OF_YEAR in temp calendar matches WEEK_OF_YEAR in global calendar */
entries.add(createEntryFromCursor(cc));
} while(cc.moveToNext());
}
In my tests, I know for a fact there is an entry at Nov. 30, 2012. With a first day of week set to Tuesday (and the entry was on Friday), this should return 1 result if the user sets the date as 1 Dec, and no result if the user sets 26 Nov. (a Monday). However, I get 1 result for both. What's wrong?!
Edit
I still really need help! I've updated the above with my current code. I'm still getting odd results. For example, with a first day of week as Monday, I'm getting this from System.out:
12-09 11:46:38.465: I/System.out(15130): Temp calendar set to 9 Dec 2012 19:29:59 GMT fdow(2) week(49), user calendar set to 9 Dec 2012 14:51:59 GMT fdow(2) week(50)
This is saying that 9 Dec, 2012 occurs in 2 different WEEK_OF_YEARs (49/50) even though both calendars have the first day of week equal to 2. Umm.. what??
Solution
I ditched getting the WEEK_OF_YEAR and followed the suggestion to get the start and end Dates for the week.
// get rollback amt
temp.setTimeInMillis(set_time);
int rollback = 0;
int dayofweek = date.get(Calendar.DAY_OF_WEEK);
while(dayofweek != temp.getFirstDayOfWeek()) {
dayofweek--;
if(dayofweek == 0) dayofweek = 7;
rollback--;
}
int rollfwd = rollback + 6;
// get start bound
temp.setTimeInMillis(set_time);
temp.roll(Calendar.DAY_OF_YEAR, rollback);
temp.set(Calendar.HOUR_OF_DAY, 0);
temp.set(Calendar.MINUTE, 1);
Date start = temp.getTime();
// get end bound
temp.setTimeInMillis(set_time);
temp.roll(Calendar.DAY_OF_YEAR, rollfwd);
temp.set(Calendar.HOUR_OF_DAY, 23);
temp.set(Calendar.MINUTE, 59);
Date end = temp.getTime();
Then I can check if the Date of the Entry is between those:
if(entrydate.after(start) && entrydate.before(end))
Can you use SimpleDateFormat in android to get week_of_year and validate the conditions for querying the user selected date.
Step 1: Get user choice for selecting the week.
eg:27
Step 2: get start of the week and ending of the week.
start of 27th week to end of 27th week.
Step 3: Use this two boundary conditions to filter your result set.
Hope this will help you to resolve your issue.
12-09 11:46:38.465: I/System.out(15130): Temp calendar set to 9 Dec
2012 19:29:59 GMT fdow(2) week(49), user calendar set to 9 Dec 2012
14:51:59 GMT fdow(2) week(50)
There is nearly a 5 hour difference between your Temp calendar value and your user calendar value.
You are outputting the date string using GMT:
temp.getTime().toGMTString()
while your Calendar objects will use the local timezone.
temp.get(Calendar.WEEK_OF_YEAR)+")
It is possible that these times are on the same day/week in GMT but not in your local timezone.
This will give you the days since monday of tha tweek
int daysSinceMonday = (7 + calendar.get(Calendar.DAY_OF_WEEK) - Calendar.MONDAY) % 7;
Use this to re-calculate the begining of your week.
Related
I'm trying to convert this time stamp value to date but its giving me wrong time. date is correct
TimeStamp : 1423821615
True Value : Fri, 13 Feb 2015 10:00:15 GMT
Android Code shows : Fri, 13 Feb 2015 15:30:15 IST
Here is the code I'm using to convert time stamp to date.
Date dt = new Date((long)timestampInSeconds * 1000);
I tried this code too but same result
public static Date getDateFromTimeStamp(long timestampInMilliseconds) {
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(timestampInMilliseconds);
return cal.getTime();
}
Date dt = getDateFromTimeStamp((long)timestampInSeconds * 1000);
I don't know what I'm doing wrong. Please help
Now I explain the whole scenario. My client is from UK and I'm from India (+5:30 ahead). He created appointment for 10 AM in UK obviously. But now I have his database in my local PC. My .NET software it shows same time as it shows in below image of SQL server. But in mobile, it doesn't. PC and mobile both are in same time zone.
I use this code to convert date to time stamp and send this time stamp to mobile app through web service
SELECT DATEDIFF(SECOND,{d '1970-01-01'}, Appointments.DateTime) AS AppointmentTimeStamp FROM Appointments
Here is image of what my .NET software displays
does it matter that record was created when database was in UK time zone. Or I'm still doing a mistake somewhere.
I didn't understand what you wanna get.
If you get time as EPOCH time, you don't have information about time zone where this time stamp was made. So, you should know time zone offset and + or minus this seconds from this time stamp.
But I think the best way to use ISO 8601 format for time stamp, it's easy to convert to any timezone what you need
for example, this code convert ISO data to local time or return current time depends on locale timezone
private long time2LocalTimeZone (String date){
//"2016-07-29T23:07:45.120+00"
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.getDefault());
try {
return sdf.parse(date).getTime();
} catch (ParseException e){
return (new Date()).getTime();
}
}
this code count your offset from GMT timezone and convert to epoch time depends on locale timezone
private long time2LocalTimeZone (long date){
TimeZone tz = TimeZone.getDefault();
Date now = new Date();
int offsetFromUtc = tz.getOffset(now.getTime()) / 1000;
return date + offsetFromUtc;
}
I'm trying to get the current day of the week and week of the year like this:
Declaring my variable like this:
Calendar calWeek;
Calendar calDay;
Setting the values like this:
calWeek = Calendar.getInstance();
calWeek.setFirstDayOfWeek(Calendar.MONDAY);
calWeek.set(Calendar.WEEK_OF_YEAR, Calendar.MONDAY);
calDay = Calendar.getInstance();
calDay.setFirstDayOfWeek(Calendar.MONDAY);
calDay.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
int currentWeek = calWeek.get(Calendar.WEEK_OF_YEAR);
int dayInWeek = calDay.get(Calendar.DAY_OF_WEEK);
currentWeek returns 2 and dayInWeek returns 2. The current week is 1 and it's Wednesday. (3rd day of the week)
Even if i change the date on my device, the output is the same, currentWeek returns 2 and dayInWeek returns 2.
Why does it always return the same date?
Best regards,
Dridia
As mentioned in Mike M's comment: you set both values to Calendar.MONDAY which is equals to 2.
Calendar.getInstance() returns an instance with the current date but if you call calendarInstance.get(Calendar.WEEK_OF_YEAR) you still get 2 because according to the docs:
When setting or getting the WEEK_OF_MONTH or WEEK_OF_YEAR fields, Calendar must determine the first week of the month or year as a reference point. The first week of a month or year is defined as the earliest seven day period beginning on getFirstDayOfWeek() and containing at least getMinimalDaysInFirstWeek() days of that month or year....
I just tried it and getMinimalDaysInFirstWeek()returns 1 by default. So you should set this to 7 days. So the first Week will begin on Monday as you expect.
One instance of Calendar is sufficient and your code should look like this:
Calendar calendarInstance = Calendar.getInstance();
calendarInstance.setFirstDayOfWeek(Calendar.MONDAY);
calendarInstance.setMinimalDaysInFirstWeek(7);
int currentWeek = calendarInstance.get(Calendar.WEEK_OF_YEAR);
int dayInWeek = calendarInstance.get(Calendar.DAY_OF_WEEK);
System.out.println("week = " + currentWeek);
System.out.println("day of week = " + dayInWeek);
prints:
week = 1
day of week = 4
P.S. 4 means Wednesday
I am writing a simple code to get the date from server in UTC and then convert it to local time based on timeDiff noted earlier. Below is the simple code:
From App.Constants interface:
SimpleDateFormat SDF_yyyyMMdd_HHmmss_SSS = new SimpleDateFormat("yyyyMMdd_HHmmss_SSS", Locale.ENGLISH);
public String getEnddate(Context context) throws ParseException {
Date date = App.Constants.SDF_yyyyMMdd_HHmmss_SSS.parse(enddate);
Log.d("Check these dates", "Check dates EventEnd: " + enddate + date.toString());
MyDate tmpDate = new MyDate(date); //May ignore this
return tmpDate.toSQLite(App.getTimeDiff(context)); //May ignore this
}
Although the result I am getting are very funny. While 80% of the dates are getting converted right, at random:
1. In some cases SDF is returning current date and time
2. In some cases SDF is returning delayed by exactly a month.
Following is a selected dump of lines from Log. In first three instances below, date returned is the current date. In fourth instance, date is delayed by a month but the time returned is the current time. In the last instance, date returned is exactly delayed by a month from the original date.
01-01 21:33:30.869 24135-24135/? D/Check these dates: Check dates EventEnd: 20151222_003819_453Fri Jan 01 21:33:19 IST 2016
01-01 21:33:30.900 24135-24135/? D/Check these dates: Check dates EventEnd: 20151222_004950_104Fri Jan 01 21:33:50 IST 2016
01-01 21:33:30.961 24135-24135/? D/Check these dates: Check dates EventEnd: 20151226_235500_000Fri Jan 01 21:33:30 IST 2016
01-01 21:33:30.971 24135-24135/? D/Check these dates: Check dates EventEnd: 20151227_060800_000Wed Jan 27 21:33:00 IST 2016
01-01 23:17:07.977 31293-31293/? D/Check these dates: Check dates EventEnd: 20151222_195508_303Fri Jan 22 19:55:08 IST 2016
0
Hoping someone can help. Else, I am just getting too tempted to write my own String to Date converted. I really hope that I don't have to!!!
EDIT:
Was too impatient, and wrote the following parser real quick. With this parser, the code is working perfectly fine, as expected. But not with SimpleDateFormat.
public static Date localDateParser(String yyyyMMdd_HHmmss_SSS){
int year = Integer.parseInt(yyyyMMdd_HHmmss_SSS.substring(0, 4));
int month = Integer.parseInt(yyyyMMdd_HHmmss_SSS.substring(4, 6)) - 1;
int day = Integer.parseInt(yyyyMMdd_HHmmss_SSS.substring(6, 8));
int hour = Integer.parseInt(yyyyMMdd_HHmmss_SSS.substring(9, 11));
int minute = Integer.parseInt(yyyyMMdd_HHmmss_SSS.substring(11, 13));
int second = Integer.parseInt(yyyyMMdd_HHmmss_SSS.substring(13, 15));
// int ms = Integer.parseInt(yyyyMMdd_HHmmss_SSS.substring(16));
GregorianCalendar cal = new GregorianCalendar(year, month, day, hour, minute, second);
new Date(cal.getTimeInMillis()).toString());
return new Date(cal.getTimeInMillis());
}
Plz change date.toString() to
App.Constants.SDF_yyyyMMdd_HHmmss_SSS.format(date).
Date.toString() is not working as you wish.
i have this code to calculate last day of the previous month of the month selected by the user. Variable monthNumber gives me the month selected my the user:
lastDayOfPreviousMonth.set(Calendar.YEAR, year);
lastDayOfPreviousMonth.set(Calendar.MONTH, monthNumber-1);
lastDayOfPreviousMonth.set(Calendar.DAY_OF_MONTH , lastDayOfPreviousMonth.getActualMaximum(Calendar.DAY_OF_MONTH));
the problem is that lastDayOfPreviousMonth.getActualMaximum(Calendar.DAY_OF_MONTH)); gives me allways 31. ¿Why?
thanks
This is not the appropriate way to obtain the maximum number of days in the previous month. Try the following:
calendarPreviousMonth.add(Calendar.MONTH, -1);
I have verified your program and just add the necessary declarations and format output:
GregorianCalendar lastDayOfPreviousMonth = new GregorianCalendar(2012, 2, 1);
int month = 5; // May (here 1-based month)
lastDayOfPreviousMonth.set(Calendar.YEAR, 2015);
// 2 for one-based month-input and previous month
lastDayOfPreviousMonth.set(Calendar.MONTH, month - 2);
lastDayOfPreviousMonth.set(
Calendar.DAY_OF_MONTH,
lastDayOfPreviousMonth.getActualMaximum(Calendar.DAY_OF_MONTH)
);
System.out.println(lastDayOfPreviousMonth.getActualMaximum(Calendar.DAY_OF_MONTH));
// output: 30
System.out.println(DateFormat.getDateInstance().format(lastDayOfPreviousMonth.getTime()));
// output: 30.04.2015
It works for me. Maybe you should check your initialization and/or use this example code on Dalvik VM.
I wrote a simple code to insert an all day event into the calendar, using the tutorial from the official site.
http://developer.android.com/guide/topics/providers/calendar-provider.html
ContentResolver cr = context.getContentResolver();
ContentValues values = new ContentValues();
values.put(Events.DTSTART, dueDate.getTime());
values.put(Events.ALL_DAY, true);
values.put(Events.DTEND, dueDate.getTime());
values.put(Events.TITLE, "Some Event");
values.put(Events.CALENDAR_ID, mCalID);
TimeZone tz = TimeZone.getDefault();
values.put(Events.EVENT_TIMEZONE, tz.getID());
Uri uri = cr.insert(Events.CONTENT_URI, values);
I found that when I opened the Google Calendar app on the my Acer device running 4.03, the date entered had been shifted back by 1 day. My local timezone is Sydney which is GMT+10.
So I went to settings changed the local time zone to American Eastern (GMT -5) and ran the same code and there was no shift in the dates. Then I changed the timezone to GMT+2, Istanbul and there was a shift in the dates. Then I changed to London GMT 0, and there was no shift.
When I did non all day events the correct times were entered into the calendar regardless of the timezone.
The closest bug report I found was this
http://code.google.com/p/android/issues/detail?id=14051
Am I missing something in the code, or have others also encountered this.
Edit
On further inspection when reading Event data using content resolver
ContentResolver cr = context.getContentResolver();
Uri uri = CalendarContract.Events.CONTENT_URI;
String selection =CalendarContract.Events._ID + "=?";
String [] selectionArgs = new String[]{String.valueOf(eventID)};
The value of the long when convert to date was the correct date and time eg. 14th Feb 2013 12.00 AEST (Sydney Time). So the problem must be in the way Google Calendar is reading in these values. When I added an all day event manually from the Calendar application in Android, and the read the time using content resolver it was the date and 11.00 am in AEST (Sydney Time), which corresponds to the +11 GMT off set in Sydney.
So all day events need to be entered in GMT to avoid this, but there is no mention of this in the documentation.
So now I am shifting the time, to avoid this problem.
A couple ideas:
time zone "independence" of all-day events (treated as if having GMT) [1] [2]
international date line
[1]"If allDay is set to 1 eventTimezone must be TIMEZONE_UTC and the time must correspond to a midnight boundary."
[2]http://developer.android.com/reference/android/provider/CalendarContract.Events.html
If my event was an all day event, I converted it to local time. This made the all day event stay on the correct date. If it is not all day I left it as normal. I don't think this is a great solution, but it works and if anyone sees a problem with it then let me know.
var startDate = yourCalendarEvent.StartDate;
if (yourCalendarEvent.IsAllDay)
{
startDate = startDate.ToLocalTime();
}
Java.Util.GregorianCalendar calStartDate = new Java.Util.GregorianCalendar(startDate.Year, startDate.Month - 1, startDate.Day, startDate.Hour, startDate.Minute, startDate.Second);
intent.PutExtra(CalendarContract.ExtraEventBeginTime, calStartDate.TimeInMillis);
The docs for CalendarContract.EventsColumns state "If allDay is set to 1 eventTimezone must be TIMEZONE_UTC and the time must correspond to a midnight boundary."
My solution to ensure that expected dates would be returned after querying the API was to a)Set the start and end event values with dates aligned to UTC. b)Adjust the time returned after querying to take the device timezone and DST into account.
a)
#Before
public void setup(){
...
mJavaCalendar = Calendar.getInstance();
mInputStart = getUtcDate(
mJavaCalendar.get(Calendar.YEAR),
mJavaCalendar.get(Calendar.MONTH),
mJavaCalendar.get(Calendar.DAY_OF_MONTH));
}
private long getUtcDate(int year, int month, int day){
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
calendar.set(year, month, day,0, 0, 0);
calendar.set(Calendar.MILLISECOND, 0);
return calendar.getTimeInMillis();
}
#Test
public void jCalAlldayTzDflt0000To2400(){
mTodayEvent.setEventStart(mInputStart);
mTodayEvent.setEventEnd(mTodayEvent.getEventStart() + DateUtils.DAY_IN_MILLIS);
mTodayEvent.setAllDay(true);
...
}
b)
public static long getTzAdjustedDate(long date){
TimeZone tzDefault = TimeZone.getDefault();
return date - tzDefault.getOffset(date);
}
public void getCorrectDate(cursor){
isAllDay() == 1 ? DateTimeUtils.getTzAdjustedDate(cursor.getLong(INST_PROJECTION_BEGIN_INDEX)) :
cursor.getLong(INST_PROJECTION_BEGIN_INDEX));
I hope this helps.