In various Android projects, I use the following static function to parse dates such as 1900-12-31. Of course, this function should be deterministic - but it turns out it is not. Why?
Normally, it parses the date 2010-10-30, for example, to the correct Date instance holding that value. But I have noticed that when I have an IntentService running at the same time and parsing some dates, this function parses the same date as above to 1983-01-20, which is one of the dates parsed in the IntentService. How can this happen?
public static Date dateFromString(String dateStr) {
SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
SimpleDateFormat mDateTimeFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.getDefault());
Date dateOut = null;
try {
if (dateStr != null) {
if (dateStr.length() == 7) {
if (dateStr.startsWith("--")) {
dateStr = "0000"+dateStr.substring(1);
}
}
else if (dateStr.length() == 6) {
if (dateStr.startsWith("-")) {
dateStr = "0000"+dateStr;
}
}
else if (dateStr.length() == 5) {
dateStr = "0000-"+dateStr;
}
else if (dateStr.matches("[0-9]{2}\\.[0-9]{2}\\.[0-9]{4}")) {
dateStr = dateStr.substring(6, 10)+"-"+dateStr.substring(3, 5)+"-"+dateStr.substring(0, 2);
}
else if (dateStr.matches("[0-9]{2}\\/[0-9]{2}\\/[0-9]{4}")) {
dateStr = dateStr.substring(6, 10)+"-"+dateStr.substring(3, 5)+"-"+dateStr.substring(0, 2);
}
else if (dateStr.matches("[0-9]{8}")) {
dateStr = dateStr.substring(0, 4)+"-"+dateStr.substring(4, 6)+"-"+dateStr.substring(6, 8);
}
if (dateStr.length() >= 20) {
String dateTimeStr = dateStr.trim();
if (dateTimeStr.endsWith("Z")) {
dateTimeStr = dateStr.substring(0, dateTimeStr.length()-1)+"+0000";
}
if (dateStr.charAt(10) == ' ') {
dateTimeStr = dateStr.substring(0, 10)+"T"+dateStr.substring(11);
}
try {
dateOut = mDateTimeFormat.parse(dateTimeStr);
}
catch (Exception e2) {
dateOut = mDateFormat.parse(dateStr);
}
}
else {
dateOut = mDateFormat.parse(dateStr);
}
}
}
catch (Exception e) {
dateOut = null;
}
return dateOut;
}
Edit: I do the parsing in my Activity's onCreate() where I start an AsyncTask that does the job. In the Activity's onStop(), a background service is started which does the same job. When I close the app (onStop()) and quickly restart it (onCreate()), both seem to be running simultaneously and the error occurrs.
The documentation of SimpleDateFormat says:
SimpleDateFormat is not thread-safe. Users should create a separate
instance for each thread.
There you go. Just create the SimpleDateFormat object separately in each thread and pass it to the method.
Related
I am doing coding in android for to know the date and time of chats app when they open last time.please help.
i have done this in my chat app with firebase so you can try this :-
create a static method which method is used in across the app :-
public static void userStatus(String status) {
FirebaseUser firebaseUser = FirebaseAuth.getInstance().getCurrentUser();
DatabaseReference reference = FirebaseDatabase.getInstance().getReference(onlineStatusTable).child(firebaseUser.getUid());
try {
HashMap<String, Object> hashMap = new HashMap<>();
hashMap.put("status", status);
reference.updateChildren(hashMap);
} catch (Exception e) {
e.printStackTrace();
}
}
and call this method in your activity onStart method:-
#Override
protected void onStart() {
userStatus(String.valueOf(System.currentTimeMillis()));
super.onStart();
}
and when you retrieve the milliseconds from server then converts like this :-
public static String getMyPrettyDate(long neededTimeMilis) {
Calendar nowTime = Calendar.getInstance();
Calendar neededTime = Calendar.getInstance();
neededTime.setTimeInMillis(neededTimeMilis);
if ((neededTime.get(Calendar.YEAR) == nowTime.get(Calendar.YEAR))) {
if ((neededTime.get(Calendar.MONTH) == nowTime.get(Calendar.MONTH))) {
if (neededTime.get(Calendar.DATE) - nowTime.get(Calendar.DATE) == 1) {
//here return like "Tomorrow at 12:00 AM/PM"
return "Tomorrow at " + DateFormat.format("hh:mm aaa", neededTime);
} else if (nowTime.get(Calendar.DATE) == neededTime.get(Calendar.DATE)) {
//here return like "Today at 12:00 AM/PM"
return "Today at " + DateFormat.format("hh:mm aaa", neededTime);
} else if (nowTime.get(Calendar.DATE) - neededTime.get(Calendar.DATE) == 1) {
//here return like "Yesterday at 12:00 AM/PM"
return "Yesterday at " + DateFormat.format("hh:mm aaa", neededTime);
} else {
//here return like "May 31, 12:00 AM/PM"
return DateFormat.format("MMMM d, hh:mm aaa", neededTime).toString();
}
} else {
//here return like "May 31, 12:00 AM/PM"
return DateFormat.format("MMMM d, hh:mm aaa", neededTime).toString();
}
} else {
//here return like "May 31 2010, 12:00 AM/PM" - it's a different year we need to show it
return DateFormat.format("MMMM dd yyyy, hh:mm aaa", neededTime).toString();
}
}
and set you textView like this :-
status.setText(getMyPrettyDate(Long.parseLong(dataSnapshot.child("status").getValue().toString())));
I am creating event App, which lists all events.
I have a problem, that when event is over, it still stays up because it was sorted by time if next event is after a week. Like this:
So, the event which was end, is need to go down and also be sorted by date.
How can I do this?
I tried to sort seperately by date and boolean, but it failed.
Or does I need to create two arraylists for ended events and upcoming?
If someone knows how to do this, please tell me, you save my day.
My code, which sorts right now:
Collections.sort(eventsList, new Comparator<TimetableEvent>() {
#Override
public int compare(TimetableEvent arg0, TimetableEvent arg1) {
SimpleDateFormat format = new SimpleDateFormat(
"dd.MM.yyyy' klo 'HH.mm");
int compareResult = 0;
try {
Date arg0Date = format.parse(arg0.getDateTime());
Date arg1Date = format.parse(arg1.getDateTime());
compareResult = arg0Date.compareTo(arg1Date);
} catch (ParseException e) {
e.printStackTrace();
compareResult = arg0.getDateTime().compareTo(arg1.getDateTime());
}
return compareResult;
}
});
Simply adapt your compare() method so that, if an event is over and the other one is not, it returns without comparing date:
#Override
public int compare(TimetableEvent arg0, TimetableEvent arg1) {
SimpleDateFormat format = new SimpleDateFormat(
"dd.MM.yyyy' klo 'HH.mm");
int compareResult = 0;
if (arg0.isOver() && !arg1.isOver()) {
return 1;
}
if (!arg0.isOver() && arg1.isOver()) {
return -1;
}
try {
Date arg0Date = format.parse(arg0.getDateTime());
Date arg1Date = format.parse(arg1.getDateTime());
compareResult = arg0Date.compareTo(arg1Date);
} catch (ParseException e) {
e.printStackTrace();
compareResult = arg0.getDateTime().compareTo(arg1.getDateTime());
}
return compareResult;
}
I am doing an app where I click the START button and get current time, and hitting STOP gets the time again. I´ve been using system time without any errors, recently I changed it to server time, which is in an Asynctask, but the app is unstable since, slowed down and exits without error messages, but on faster connections it can process. Any idea why? This is my code:
class getDST2 extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... arg0) {
try {
TimeTCPClient client = new TimeTCPClient();
try {
client.setDefaultTimeout(60000);
client.connect("time.nist.gov");
simpledate = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
do_casu = simpledate.format(client.getDate());
} finally {
client.disconnect();
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
protected void onPostExecute(Void result) {
getDSTdone = true;
}
}
Also doing a graphic timer of the current time since Start was clicked so I need to get server time every second inside a handler.. code:
handler.post(r = new Runnable() {
public void run() {
hasStartedtt2 = true;
calendar = Calendar.getInstance();
simpledate = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
new getDST2().execute(); // THIS IS THE ASynctask, returns the "do_casu" String
zaciatok_hour = zaciatok.substring(11, 13);
zaciatok_minute = zaciatok.substring(14, 16);
koniec_hour = do_casu.substring(11, 13);
koniec_minute = do_casu.substring(14, 16);
zaciatok_sekundy = zaciatok.substring(17, 19);
koniec_sekundy = do_casu.substring(17, 19);
final_hour = ((Integer.parseInt(koniec_hour) - Integer.parseInt(zaciatok_hour)));
final_minute = Integer.parseInt(koniec_minute) - Integer.parseInt(zaciatok_minute);
final_seconds = Integer.parseInt(koniec_sekundy) - Integer.parseInt(zaciatok_sekundy) - 1;
}
});
Handler is called every second.
ServerTimeThread sth = new ServerTimeThread();
sth.start();
from_time = simpledate.format(sth.time);
when you call 'sth.time',the thread just start and is still in progress.
'time' is remain uninitialized,it is init at end of thread
So when accessing 'time',it is null absolutely.
2 way for AsyncTask
Blocking operation:
public class NTPDateTask extends AsyncTask<Void,Void,Date> {
#Override
protected Date doInBackground(Void... voids) {
Date date=fetchYourDate();
//fetch your date here
return date;
}
}
then call
Date result = new NTPDateTask().execute().get();
Non-Blocking operation(Callback pattern):
public class NTPDateTask extends AsyncTask<Void,Void,Date> {
#Override
protected Date doInBackground(Void... voids) {
Date date = fetchYourDate();
//fetch your date here
return date;
}
#Override
protected void onPostExecute(Date date) {
//this is 'callback'
//do the thing you want when task finish
//onPostExecute is called when doInBackground finished,and it runs on UIThread
}
}
then
new NTPDateTask().execute();
EDIT:
class TCPTimeDisplayWorker implements Runnable {
static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss");
boolean isActive = true;
private Handler targetHandler;
public TCPTimeDisplayWorker(Handler targetHandler) {
//pass the handler ref here
this.targetHandler = targetHandler;
}
#Override
public void run() {
while (isActive) {
long startTime = System.currentTimeMillis();
Date date = fetchDateFromTCPClient();
//fetch Server Date here
String currentDateText = simpleDateFormat.format(date);
targetHandler.sendMessage(Message.obtain(targetHandler, 0, currentDateText));
long endTime = System.currentTimeMillis();
long lapse = endTime - startTime;
if (lapse < 1000) {
try {
Thread.sleep(1000 - lapse);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
Handler:
// Non-static inner class will hold outer-class reference,may risk in memory leak
static class MainHandler extends Handler {
private WeakReference<TextView> textViewWeakReference;
// declare as WeakRef to avoid memory leak
public MainHandler(Looper looper, WeakReference<TextView> textViewWeakReference) {
super(looper);
this.textViewWeakReference = textViewWeakReference;
}
#Override
public void handleMessage(Message msg) {
if (textViewWeakReference.get() != null) {
//handle the message from message queue here
String text = (String) msg.obj;
textViewWeakReference.get().setText(text);
}
}
}
then
// must use the same handler to send msg from Background thread and
// handle at Main Thread
// a handler create on a thread will bound to that thread
mainHandler = new MainHandler(Looper.getMainLooper(), new WeakReference<>(mTextViewSystemTime));
new Thread(new TCPTimeDisplayWorker(mainHandler)).start();
btw,CamelCase is the common naming convention in Java.
Hope these are helpful.
I have two datepickers in my activity.
I want startdate of datePickerB dialog to be updated automatically based on date selected in datePickerA dialog.
I use setMinDate for datePickerB. setMinDate works fine for the very first time. But couldn't update or reset the mindate of datePickerB for consecutive updates in datePickerA. Kindly help.
Searched for all possible solutions but of no use. Kindly help
Below is my code. The code used in oncreate gets executed , but further setMinDate function called in HandleResponse ( this is the function that gets called once datepickerA is set )
//On OnCreate
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.DAY_OF_YEAR, 1);
Date tomorrow = calendar.getTime();
long t = tomorrow.getTime();
fromDatePicker.getDatePicker().setMinDate(t);
//
toDatePicker.getDatePicker().setMinDate(t);
public void HandleResponse(Response response)
{
String sqlRes = "";
try {
String sResJson = response.body().string();
JSONObject jReader = new JSONObject(sResJson);
JSONObject jRes = jReader.getJSONObject("Result");
sqlRes = jRes.getString("res");
final int sqlMilkQty = jRes.getInt("qty");
String enddate = jRes.getString("date");
Date d = null;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
d = sdf.parse(enddate);
} catch (ParseException e) {
e.printStackTrace();
}
if (d != null && fromDate!= null) {
long t = d.getTime();
long t1 = fromDate.getTime();
toDatePicker.getDatePicker().setMinDate(t1);
toDatePicker.getDatePicker().setMaxDate(t);
}
Handler mainHandler = new Handler(Looper.getMainLooper());
if (sqlRes.equals("PASS"))
{
mainHandler.post(new Runnable() {
#Override
public void run() {
milkQuantity = sqlMilkQty;
txtMilkQuantity.setText(String.valueOf(milkQuantity));
}
});
}
else {
}
} catch (IOException e) {
DisplayError();
}
catch (JSONException e) {
DisplayError();
}
}
My Question is How to compare two time between startTime and endTime,
Comparison two time.
Start time
End time.
I am using the TimePickerDialog for fetching time and I am using one method Which pass the parameter like long for startTime and endTime, I am using like this,
//Method:
boolean isTimeAfter(long startTime, long endTime) {
if (endTime < startTime) {
return false;
} else {
return true;
}
}
String strStartTime = edtStartTime.getText().toString();
String strEndTime = edtEndTime.getText().toString();
long lStartTime = Long.valueOf(strStartTime);
long lEndTime = Long.valueOf(strEndTime);
if (isTimeAfter(lStartTime, lEndTime)) {
} else {
}
Get The Error:
java.lang.NumberFormatException: Invalid long: "10:52"
How to compare two time. Please suggest me.
First of all you have to convert your time string in to SimpleDateFormat like below:
SimpleDateFormat sdf = new SimpleDateFormat("hh:mm");
Date inTime = sdf.parse(strStartTime);
Date outTime = sdf.parse(strEndTime);
Then call your method like below:
if (isTimeAfter(inTime, outTime)) {
} else {
}
boolean isTimeAfter(Date startTime, Date endTime) {
if (endTime.before(startTime)) { //Same way you can check with after() method also.
return false;
} else {
return true;
}
}
Also you can compare, greater & less startTime & endTime.
int dateDelta = inTime.compareTo(outTime);
switch (dateDelta) {
case 0:
//startTime and endTime not **Equal**
break;
case 1:
//endTime is **Greater** then startTime
break;
case -1:
//startTime is **Greater** then endTime
break;
}
What about this :
SimpleDateFormat sdf = new SimpleDateFormat("hh:mm");
public static boolean isTimeAfter(Date startTime, Date endTime) {
return !endTime.before(startTime);
}
}
try {
Date inTime = sdf.parse(mEntryTime);
Date outTime = sdf.parse(mExitTime);
if (Config.isTimeAfter(inTime, outTime)) {
//Toast.makeText(AddActivity.this, "Time validation success", Toast.LENGTH_LONG).show();
}
else {
Toast.makeText(AddActivity.this, "Exit time must be greater then entry time", Toast.LENGTH_LONG).show();
}
} catch (ParseException e) {
e.printStackTrace();
//Toast.makeText(AddActivity.this, "Parse error", Toast.LENGTH_LONG).show();
}