I have some moment in time in UTC timestamp. I create a DateTime object from it, and then try to enrich it with "(today)" or "(tomorrow)" explanation if it is so:
DateTime dateTimeUtc = new DateTime(this.timeUtc, DateTimeZone.UTC);
DateTimeFormatter dateTimeFormatter = DateTimeFormat.mediumDate();
String resultingString = dateTimeUtc.withZone(DateTimeZone.forTimeZone(TimeZone.getDefault()))
.toString(dateTimeFormatter);
if(dateTimeUtc.getDayOfYear() == DateTime.now(DateTimeZone.UTC).getDayOfYear()) {
resultingString += " (" + context.getResources().getString(R.string.today_caption) + ")";
} else if(dateTimeUtc.getDayOfYear() == DateTime.now(DateTimeZone.UTC).plusDays(1).getDayOfYear()) {
resultingString += " (" + context.getResources().getString(R.string.tomorrow_caption) + ")";
}
But - surprisingly - my app does a TimeZone conversion somewhere. Device is set for eastern europian time (GMT+3 currently) and it works like this: 2 june 2:59 AM is treated like today (0_o) 2 june 3:01 is already a tomorrow.
Can someone point to an error?
P. S.: if there's a better way to qualify DateTime as 'today' or 'tomorrow' - I would be great to see any ideas.
Since no answer provided, I'll post workaround of my own. Though still have no idea why comparison of two UTC-zoned timestamp'ed days of year gives user's timezone offset.
Here's the code that works correctly for me:
if(dateTimeUtc.withZone(userZone).getDayOfYear() == DateTime.now(DateTimeZone.UTC).withZone(userZone)
.getDayOfYear()) {
resultingString += " (" + context.getResources().getString(R.string.today_caption) + ")";
} else if(dateTimeUtc.withZone(userZone).getDayOfYear() == DateTime.now(DateTimeZone.UTC).withZone(userZone)
.plusDays(1).getDayOfYear()) {
resultingString += " (" + context.getResources().getString(R.string.tomorrow_caption) + ")";
}
this produces correct check if given day is in interval from now till start of tomorrow or from start of tomorrow till start of the day after.
Related
Good evening, I have a problem with binding and editable.
binding.editText.text = String.format("%02d", picker.hour - 12) + " : " +
String.format("%02d", picker.minute) + "PM"
I know ".text" requires a editable, but how do i cast it?
I tried all type of normal casting but it seems not to be working.
The error disappears if i delete the "="
Casting is the wrong word to describe it. Casting is promising the compiler that the object already is of another type. And a String is not an Editable, so casting it would cause a crash with ClassCastException. The correct question would be how to convert the String to an Editable.
But you don't need to anyway. The text property expects an Editable, but there is also a setText function that accepts any CharSequence, which includes String.
binding.editText.setText(
String.format("%02d", picker.hour - 12) + " : " + String.format("%02d", picker.minute) + "PM"
)
And a tip, you can use format as an extension function to make it more concise.
binding.editText.setText(
"%02d".format(picker.hour - 12) + " : " + "%02d".format(picker.minute) + "PM"
)
And you can use string template format to make the concatenation more concise, too:
binding.editText.setText("${"%02d".format(picker.hour - 12)}:${"%02d".format(picker.minute)}PM")
i have a question to Google Fit.
I am creating a step counter (oh wonder g). This i have already done so far and it not really hard.
But now we come to my problem. I am only reading the steps with the Sensor API. The issue is, i can add new data via for example the Google Fit app and it will be counted in my app too. This introduces cheating and i do not want this.
So i need to have a way to only read "device created" data and not manually added data. Is there a nice way to to this?
From the SDK documentation it is not really clear how to proceed here.
So i need to have a way to only read "device created" data and not
manually added data. Is there a nice way to to this?
You will want to use Private Custom Data Types to achieve that. Read about the different types of Fitness data you can upload to Google Fit here.
1. Public data types
Standard data types provided by the platform, like com.google.step_count.delta. Any app can read and write data of
these types. For more information, see Public Data Types.
2. Private custom data types
Custom data types defined by an specific app. Only the app that defines the data type can read and write data
of this type. For more information, see Custom Data Types.
3. Shareable data types
Custom data types submitted to the platform by an app developer. Once approved, any app can read data of a
shareable type, but only whitelisted apps as specified by the
developer can write data of that shareable type. For more information,
see Shareable Data Types.
I was able to do this with the help of this alogrithm. But remember due to Android fragmentation this code still removes some of the user's data and count it as penalty
private String dumpDataSet(DataSet dataSet, int x) {
List<String> days = new ArrayList<>();
days.add("Monday");
days.add("Tuesday");
days.add("Wednesday");
days.add("Thursday");
days.add("Friday");
days.add("Saturday");
days.add("Sunday");
String day = days.get(Math.round(x / 24));
Log.d(TAG, "\tDay: " + day);
Log.i(TAG, "Data returned for Data type: " + dataSet.getDataType().getName());
DateFormat dateFormat = getTimeInstance();
String text = "";
try {
for (DataPoint dp : dataSet.getDataPoints()) {
Log.i(TAG, "\tStepCount getStreamName: " + dp.getOriginalDataSource().getStreamName());
Log.i(TAG, "\tStepCount getStreamIdentifier: " + dp.getOriginalDataSource().getStreamIdentifier());
Log.i(TAG, "\tStepCount App Type: " + dp.getDataType().getName());
Log.i(TAG, "\tStepCount Type: " + dp.getOriginalDataSource().getType());
for (Field field : dp.getDataType().getFields()) {
Log.i(TAG, "\tField: " + field.getName() + " Value: " + dp.getValue(field));
text += dp.getValue(field);
String si[] = dp.getOriginalDataSource().getStreamIdentifier().toLowerCase().split(":");
if ((((si[si.length - 1].contains("soft")) || (si[si.length - 1].contains("step"))) && si[si.length - 1].contains("counter"))) {
totalSteps += Integer.parseInt(dp.getValue(field).toString());
Log.d(TAG, "\tStepCount" + " Added Steps -> " + dp.getValue(field) + " steps");
text += "\n\n";
} else {
Log.e(TAG, "\tStepCount PENALTY ---------------------------------------------------------------");
Log.e(TAG, "\tDay = " + day + " | Hour Number = " + x + " | StepCount" + " PENALTY DEDUCTED -> " + dp.getValue(field) + " steps");
Log.e(TAG, "\tStepCount PENALTY getStreamIdentifier: " + dp.getOriginalDataSource().getStreamIdentifier());
Log.e(TAG, "\tStepCount PENALTY getStreamName: " + dp.getOriginalDataSource().getStreamName());
Log.e(TAG, "\tStepCount PENALTY App Type: " + dp.getDataType().getName());
Log.e(TAG, "\tStepCount PENALTY Type: " + dp.getOriginalDataSource().getType());
Log.e(TAG, "\tStepCount PENALTY ---------------------------------------------------------------");
}
}
}
} catch (Exception ex) {
ex.getStackTrace();
}
return text;
}
----- UPDATE -----
You can also call
DataPoint.getOriginalDataSource().getAppPackageName()
to filter out smartwatches and other apps.
I tried as suggested by Ali Shah lakhani but
DataPoint.getOriginalDataSource().getAppPackageName();
/*I also tried but could not achieve what I wanted*/
DataPoint.getOriginalDataSource().getStreamName();
DataPoint.getOriginalDataSource().getStreamIdentifier();
did not work at least for me while retrieving data. I ended up using readDailyTotalFromLocalDevice() as shown below in order to capture steps captured by device only.
Fitness.HistoryApi.readDailyTotalFromLocalDevice(mApiClient, DataType.TYPE_STEP_COUNT_DELTA).await(1, TimeUnit.MINUTES)
I cross checked the same with some of the apps that avoids manual entries in their app and the count provided by the function above is exactly the same.
Note: If a user is having multiple devices and is using the app on all of them, readDailyTotalFromLocalDevice() will have different value for each and every device since the function is responsible for returning device specific data only.
When my app starts up for the first time, I want to detect the user's current locale and set a SharedPreference accordingly. I'm grabbing the user's current locale from getResources(), which I've come to understand is set when the app starts for the first time:
// Set the locale
Locale locale = getResources().getConfiguration().locale;
if(locale != Locale.US)
{
Log.i("ActivityDownloader", "Locale: " + locale.toString() + ", (" + Locale.US.toString() + ")");
}
Unfortunately, I'm seeing that log entry in the console with the following text:
I/ActivityDownloader: Locale: en_US, (en_US)
Why don't the two Locale match? Should I be matching Locale.toString() instead?
You need to use the equals() method. The == and != operators won't work for this.
Locale locale = getResources().getConfiguration().locale;
if(!locale.equals(Locale.US))
{
Log.i("ActivityDownloader", "Locale: " + locale.toString() + ", (" + Locale.US.toString() + ")");
}
I believe this is because == and != will compare references rather than the value. See https://stackoverflow.com/a/767379/935779
In a database I have saved the date in form of 3 columns: Year, Month, Day_of_Month
( I know it might not be a best way to save the date but I make certain other queries for which this format felt suitable.)
Now I wish to get all the rows where the date is in between two specified dates. I went through previous stackoverflow questions, but most of them have saved the date as a single entity.
This is how I tried:
I have a MySqLiteHelper class with all the column names declared. I also create the table there. COLUMN_DATE_YEAR, COLUMN_DATE_MONTH and COLUMN_DATE_DAY are the string storing the column names.
int fyear, fmonth, fday; // I populate those initial date values
int tyear, tmonth, tday; // I populate those target date values
String selection = MySQLiteHelper.COLUMN_DATE_YEAR + " >= '"+fyear+"' AND "+ MySQLiteHelper.COLUMN_DATE_DAY + " >= '"+fday+"' AND "
+ MySQLiteHelper.COLUMN_DATE_MONTH + " >= '"+fmonth+"' AND " + MySQLiteHelper.COLUMN_DATE_YEAR + " <= '"+tyear+"' AND "
+ MySQLiteHelper.COLUMN_DATE_DAY + " <= '"+ tday+"' AND "+ MySQLiteHelper.COLUMN_DATE_MONTH + " <= '"+tmonth+"'";
String []column = {MySQLiteHelper.COLUMN_MOOD_LEVEL};
Cursor cursor = database.query(MySQLiteHelper.TABLE_NAMES, column, selection, null, null, null, null);
Now the problem with this approach is that it will give no results for the query between 25 Feb 2013 and 17 March 2013 as the date 25th > 17th, even though the month 2 < 3. This might require some kind of nested where clause. However I am unable to form a nested 'Where' using '.query' method.
Please suggest a way to query for the entries stored in between these two dates. Thanks in advance.
There's no reason why you shouldn't be able to run a somewhat more complex WHERE clause, as follows (for date >= 2013-02-17):
( YEAR > 2013 OR ( YEAR = 2013 AND ( MONTH > 2 OR ( MONTH = 2 AND DAY >= 17 ) ) ) )
This will work, but it's for from optimal. You'd be better off correcting your database design.
Correction: You must fix your database design. Either store the date as DATE type or as ISO string: yyyy-mm-dd.
Bonus: Say you have the following right now:
CREATE TABLE theTable(
....
THEYEAR TEXT,
THEMONTH TEXT,
THEDAY TEXT );
To convert the date to a usable format, you can simply run the following:
ALTER TABLE theTable
ADD COLUMN THEDATE TEXT;
UPDATE theTable
SET THEDATE = THEYEAR || substr( '0' || '-' || THEMONTH, -2, 2 ) || '-' || substr( '0' || THEDAY, -2, 2 );
Once you've done that, you can then query using the BETWEEN clause.
Using your current schema, try reordering your WHERE clause. You need to compare the largest columns first, i.e. year, month, day. With your current year, day, month you cannot accurately compare dates that cross over into new months.
For example: day >= 25 and day <= 17 creates an invalid range. It doesn't account for the correct range: >25, wrap to 1, then <17...
Without changing the table structure the below query will work for you, try it
select * from TableName WHERE (10000*ColumnYear+100*ColumnMonth+ColumnDay >= 20131009) and (10000*ColumnYear+100*ColumnMonth+ColumnDay <= 20131121);
why duration column in calendar Evens table does not get value set via provider?
ContentValues event = new ContentValues();
if(allDay==1) {
long days = (dtend - dtstart + DateUtils.DAY_IN_MILLIS - 1) / DateUtils.DAY_IN_MILLIS;
event.put("duration", "P" + days + "D");
} else {
event.put("duration", "P" + ((dtend-dtstart)/DateUtils.SECOND_IN_MILLIS) + "S");
}
Uri eventsUri =Uri.parse("content://com.android.calendar/events")
cr.insert(eventsUri, event);
Are you sure you are not dividing by zero?
The DateUtils.SECOND_IN_MILLIS might get zero as value and then it will not perform the calculation (it should crash I presume).
You might want to check it out. I'm no Android programmer, but that's the first thing I would check assuming the code has a valid syntax.