I am trying to return a query of Calendar events sorted by date and time so that I can iterate through them. I have queried it like so:
private Cursor mCursor = null;
private static final String[] COLS = new String[]{CalendarContract.Events.TITLE, CalendarContract.Events.DTSTART, CalendarContract.Events.AVAILABILITY};
mCursor = getContentResolver().query(CalendarContract.Events.CONTENT_URI, COLS, null, null, null);
mCursor.moveToLast();
This works great except it seems to return the calendar events based on when it was created and not by date and time. For example, if I create a new event for December 25, 2012, it will show up as the last result.
My end goal is that I would like to find the first event that starts before the current time. For example, if it is currently 8:00am, I want to find the first event that starts before 8:00am. I want to then check the duration of that event to see if it is a currently ongoing event.
Is there an easy way to return a query sorted by date and time or will I have to implement a sort after the results are queried? Better yet, is there a simple way to find the first event before the current time?
maybe this?
private Cursor mCursor = null;
private static final String[] COLS = new String[]{CalendarContract.Events.TITLE, CalendarContract.Events.DTSTART, CalendarContract.Events.AVAILABILITY};
mCursor = getContentResolver().query(CalendarContract.Events.CONTENT_URI, COLS, null, null, CalendarContract.Events.DTSTART + " ASC");
mCursor.moveToLast();
Another way is like this.
Collections.sort(dateList, new Comparator<Date>(){
public int compare(Date date1, Date date2){
return date1.after(date2);
}
});
Related
All!
My code:
This method needs to check current date and if it is changed it will make new record in db.
public static void updateHintBase(SQLiteOpenHelper database)
{
String currentDate = getDateInString();
SQLiteDatabase db = database.getReadableDatabase();
Cursor cursor = db.query("HINTS",
new String[]{"CURRENT_DATE"},
"CURRENT_DATE = ?",
new String[]{currentDate},
null, null, null);
int countRow = cursor.getCount();
cursor.close();
if (countRow==0)
{
ContentValues values = new ContentValues();
values.put("CURRENT_DATE", currentDate);
values.put("SPENT", 0);
values.put("TOTAL", TOTAL_HINTS);
db.insert("HINTS", null, values);
}
db.close();
}
This method transforms date to String :
private static String getDateInString()
{
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String date = sdf.format(new Date());
return date;
}
Table structure:
db.execSQL("CREATE TABLE HINTS (CURRENT_DATE TEXT PRIMARY KEY , "
+ "SPENT INTEGER,"
+ "TOTAL INTEGER);");
But my code doesn't work. First time it works, but the second time when date was changed my first method finds element in cursor anyway...
For example:
1) Today 16.01.2017. My application was executed. Everything is all right.
2) Today 18.01.2017. My application was executed and I expect that method cursor.getCount() will return to me 0 and new row with new date will be created. But it returns to me 1. etc.
You may have to set cursor to cursor.MoveToNext() You are also closing the cursor before you get the information which may be the problem. Lastly looping through the cursor is the most efficient way to get more that one piece of information.
Please try this query:
cursor = db.rawQuery("select count(YOUR_ID) from HINTS where CURRENT_DATE = ? ", new String[] {currentDate});
Oh! I found my mistake!
Word "CURRENT_DATE" is reserved by SQL.
https://docs.oracle.com/cd/B28359_01/server.111/b28286/functions037.htm#SQLRF00628
That's why my code works incorrect.
I change "CURRENT_DATE" to "TODAY" an now it works fine.
I try to implement one way synchronization with android calendar events (I need original events - not event instances). So, I have the following query:
String[] projection = new String[]{
CalendarContract.Events.DTSTART,
CalendarContract.Events.EVENT_TIMEZONE,
CalendarContract.Events.DTEND,
CalendarContract.Events.EVENT_END_TIMEZONE,
CalendarContract.Events.DURATION
};
String selection = null;
String[] args = new String[0];
String sort = CalendarContract.Events.DTSTART + " ASC";
Cursor cursor = getContentResolver().query(CalendarContract.Events.CONTENT_URI, projection, selection, args, sort);
According to developer docs for recurrent events dtstart and duration are required but when I create event through Google calendar and receive it later in my code I have dtend = 0 and duration = null.
Integer dtend = cursor.getLong(2);
String duration = cursor.getString(4);
Why it may happen?
I have an issue with indexes in my original application. CalendarContract.Events.DURATION column solves the problem. It has single event duration in RFC2445 format. I just need to parse it.
I am accessing Android MMS database to get the date of MMS message:
Uri mmsUri = Uri.parse("content://mms/");
ContentResolver contentResolver = getContentResolver();
String[] projection = {"_id", "date"};
Cursor cursor = contentResolver.query(mmsUri, projection, null, null, null);
long dateVal = cursor.getLong(cursor.getColumnIndex("date"));
//This date is always 1970
Date mmsDate = new Date(dateVal);
But the date I get is always 1970. Then, I found an answer for this. I need to set the projection to null (to return all columns) and then use the following code to get date value:
//A mystery column of index 2
long timestamp = cursor.getLong(2) * 1000;
//It works !
Date mmsDate = new Date(timestamp);
Everything until here is fine. But, now instead of geting all rows from MMS database, I need to select those rows which were sent after a certain date, which means I need to use selection & selection argument. Something like:
String selection = NAME_OF_MYSTERY_COLUMN_IDX_2 > minDate
Cursor cursor = contentResolver.query(mmsUri, projection, selection, null, null);
But I have no idea what is the name of the column with index 2, how could I achieve what I need ? Is there a workaround?
Your first code block is correct, except for the Date instantiation. That constructor expects the time in milliseconds, but the MMS table keeps dates in seconds. To correct this, simply multiply the value returned from the query by 1000.
Date mmsDate = new Date(dateVal * 1000);
For future reference, the Cursor#getColumnName() method will give you the String name for a given column index.
You can try this.
String selection = "date_sent" > minDate
https://developer.android.com/reference/android/provider/Telephony.BaseMmsColumns.html#DATE_SENT
The basic idea of what I want to achieve is to make a comparison between the current Android system date and an existing date in a SQlite database.
The idea is to 1.) If the database does not contain contain a entry with today's date, then allow new entry
2.) If the database already contains an entry from today's date, then revoke entry and output error message.
My DBAdapter currently has a method that does the following:
public Cursor getDate(String date) {
String where = KEY_DATE + "=" + date;
Cursor c = db.query(true, DATABASE_TABLE, ALL_KEYS,
where, null, null, null, null, null);
if (c !=null) {
c.moveToFirst();
}
return c;
}
and the method i'm using to make the comparison is:
public void addRecord (View view){
db.open();
Cursor cursor = db.getDate(dateString);
if (cursor.moveToFirst()){
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Date");
builder.setMessage("Entry for today exists, would you like to update this instead?"); builder.setPositiveButton("OK", null);
#SuppressWarnings("unused")
AlertDialog dialog = builder.show();
db.close();
}
else{
Do other work..
both Date's used for comparison is formatted using this code:
long longDate = System.currentTimeMillis();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String dateString = sdf.format(longDate);
where I'm simply calling 'dateString'
My trouble is that it doesn't perform the correct checks and skips my else statement completely even tho i know there is an existing 'date' in the database. Is my SQL statement correct?
Try setting up the query like this:
db.query(true, DATABASE_TABLE, ALL_KEYS, KEY_DATE + "=?", new String[] {date}, null, null, null, null);
I use dates on my database, But I save them as a long value with the getDate() function.
Also I have found problems depending on the type of Date variable you use.
I like java.util.Date and never ever use the sql date variable.
I do where conditions for my data and all comparison are by getTime() which is a Long value.
With the long value you get from the database just do new Date( longValue ) and that way you get the correct date variable.
I'm trying to write a class to add events to a user's calendar in the background (not using intents). I need to ultimately be able to add as many as 7 events in a loop, so I can't do this with the approach where we turn control over to the calendar for the user to confirm.
Unfortunately, I'm not getting anywhere. The only feedback that I get from the logcat is a warning: Cursor finalized without prior close()
#TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
public class AddToCalendar {
Context context;
// Projection array. Creating indices for this array instead of doing
// dynamic lookups improves performance.
public static final String[] EVENT_PROJECTION = new String[] {
Calendars._ID, // 0
Calendars.ACCOUNT_NAME, // 1
Calendars.CALENDAR_DISPLAY_NAME, // 2
Calendars.OWNER_ACCOUNT // 3
};
// The indices for the projection array above.
private static final int PROJECTION_ID_INDEX = 0;
private static final int PROJECTION_ACCOUNT_NAME_INDEX = 1;
private static final int PROJECTION_DISPLAY_NAME_INDEX = 2;
private static final int PROJECTION_OWNER_ACCOUNT_INDEX = 3;
public AddToCalendar (Context context) {
this.context = context;
}
public Cursor getCalendars() {
Cursor cursor = null;
ContentResolver cr = context.getContentResolver();
Uri uri = Calendars.CONTENT_URI;
String selection = "((" + Calendars.ACCOUNT_NAME + " = ?) AND ("
+ Calendars.ACCOUNT_TYPE + " = ?) AND ("
+ Calendars.OWNER_ACCOUNT + " = ?))";
String[] selectionArgs = new String[] {"sampleuser#gmail.com", "com.google",
"sampleuser#gmail.com"};
// Submit the query and get a Cursor object back.
cursor = cr.query(uri, EVENT_PROJECTION, selection, selectionArgs, null);
return cursor;
}
public void addEvent(Cursor cursor, String type, String location, String description, Date workout_date) {
System.err.println("adding event");
while (cursor.moveToNext()) {
String displayName = null;
String accountName = null;
String ownerName = null;
// Get the field values
long calID = 0;
calID = cursor.getLong(PROJECTION_ID_INDEX);
displayName = cursor.getString(PROJECTION_DISPLAY_NAME_INDEX);
accountName = cursor.getString(PROJECTION_ACCOUNT_NAME_INDEX);
ownerName = cursor.getString(PROJECTION_OWNER_ACCOUNT_INDEX);
System.err.printf("Calendar: %s\n", displayName);
long startMillis = 0;
long endMillis = 0;
Calendar beginTime = Calendar.getInstance();
beginTime.set(2014, 1, 26, 7, 30);
startMillis = beginTime.getTimeInMillis();
Calendar endTime = Calendar.getInstance();
endTime.set(2014, 1, 26, 8, 45);
endMillis = endTime.getTimeInMillis();
ContentResolver cr = context.getContentResolver();
ContentValues values = new ContentValues();
values.put(Events.DTSTART, startMillis);
values.put(Events.DTEND, endMillis);
values.put(Events.TITLE, type);
values.put(Events.EVENT_LOCATION, location);
values.put(Events.DESCRIPTION, description);
values.put(Events.CALENDAR_ID, calID);
values.put(Events.EVENT_TIMEZONE, "America/Los_Angeles");
cr.insert(Events.CONTENT_URI, values);
}
}
}
Most of this is pulled together from http://developer.android.com/guide/topics/providers/calendar-provider.html but it's just not working. Other than the warning that I mentioned, it all "appears" to work, except for the minor detail that nothing shows up on the calendar.
How do I write the getCalendars() query in a general way to get all of the calendars that might be on a user's device? Right now, you can see that I still have the language from the android site.
Any help is appreciated. Thank you.
EDIT: Andrew T pointed out that I have an off-by-one error since the months are zero-based, so I changed my hard coded date to be month 0. I also added a cursor.close() after my while loop. However, I still didn't have anything on my calendar.
One thing that I noticed was that I wasn't entering the while loop. So I took out the loop. When I hard-code the calID variable to 1, I finally get a calendar entry, but this concerns me. I thought that the point of getting the calendars was that a user might use multiple calendars on their device, and the cursor was a way of iterating over each of these calendars. Am I wrong about that?
If hardcoding calID to 1 will solve my problem, I'm fine with that, but I want to make sure that I understand this and am not relying on an ad hoc solution. Thanks again!
The warning is caused by not closing the Calendar Cursor after inserting the events. Call cursor.close() to close it.
Also, have you checked the events on February? I'm afraid you have off-by-1 issue with how month works in Java's Calendar. (Month starts with 0, which is Calendar.JANUARY)
EDIT :
It seems that there is a problem with getCalendars(), particularly on String selection = ... which returns empty Cursor. Also, with this approach, there is a possibility that the event will be added to multiple calendars, which might not be desired.
My idea is to create a ListActivity to list all calendars to let user chooses which calendar he wants to use. With this, you can also save the calendar ID to SharedPreference and use it when creating event conveniently.
I think you can use cursor = cr.query(uri, EVENT_PROJECTION, null, null, null); to list all calendars on the device.