I'm having a problem and I absolutely can't wrap my head around it. I am inexperienced in Java (or any language, for that matter), so excuse me if this is a stupid question.
From what I can tell, the format() method from java.time.format.DateTimeFormatter is not working how I thought it did. I am consistently getting the following error message (CLI):
Watch.java:609: error: cannot find symbol
String dateTimeDisplay = dateTime.format(dateTimeFormat);
^
symbol: method format(DateTimeFormatter)
location: variable dateTime of type Object
1 error
And here are the bits of code I think are relevant:
import java.time.ZonedDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
public class Watch {
protected int hour, hourTens, hourOnes, minute, minuteTens, minuteOnes, amPM;
public void watchMethod(String userInput) {
Object dateTime; // Create reference to object called dateTime
switch (userInput) {
case "1":
ZonedDateTime dateTimeHere = ZonedDateTime.now();
hour = dateTimeHere.getHour();
minute = dateTimeHere.getMinute();
// amPM is used exclusively to display AM/PM or a heart (see lines 580 to 567).
amPM = dateTimeHere.getHour();
dateTime = dateTimeHere;
break;
case "2":
ZonedDateTime dateTimeThere = ZonedDateTime.now(ZoneId.of("Europe/Paris"));
hour = dateTimeThere.getHour();
minute = dateTimeThere.getMinute();
// amPM is used exclusively to display AM/PM or a heart (see lines 560 to 567).
amPM = dateTimeThere.getHour();
dateTime = dateTimeThere;
break;
case "3":
hour = -1;
minute = -1;
break;
}
// There is some code that prints things to console depending on the hour, minute, and amPM variables.
// I don't think this is relevant, but that's what's here.
// The following code prints out the actual date and time from a ZonedDateTime object.
DateTimeFormatter dateTimeFormat = DateTimeFormatter.ofPattern("hh:mm a 'on' EEEE, MMMM dd, yyyy");
String dateTimeDisplay = dateTime.format(dateTimeFormat); // ERROR
System.out.print("\nIt is currently " + dateTimeDisplay + "\n");
}
}
This is all one class.
I have checked that my imports are correct and that there are no misspellings anywhere! This is what other questions related to my problem have led me to believe was the issue, but it doesn't seem to be the case.
I'm also not very familiar with using Object as a reference type, so if that could be what's causing the problem, I'm not surprised. It's all I could figure out to break dateTimeHere/dateTimeThere out of the switch block.
Anyway, I'd greatly appreciate any help I receive.
QUICK EDIT: I also figured that if there were no suitable dateTime object (i.e. case "3"), this would also cause an error. I briefly added an if/else statement to remedy this, with some code in case "3" indicating that dateTime was null, but this did absolutely nothing. Let me know if I should re-add this, though.
EDIT: Thanks to a comment from #MarsAtomic, I see that this post could have used another read-through. My problem is that at the end of my code, I want to print out the ZonedDateTime data the switch statement retrieved, whether that is from the user's computer location or "Paris/Europe". Eventually, that "Paris/Europe" string will (ideally) have some user input from a subclass (as is the case with userInput, but that particular string was just for choosing one of the 3 cases already shown).
You probably meant to declare dateTime as a ZonedDateTime, as Object's definition does not include a format method.
Revised code:
ZonedDateTime dateTime = null; // Create reference to object called dateTime
//...
DateTimeFormatter dateTimeFormat = DateTimeFormatter.ofPattern("hh:mm a 'on' EEEE, MMMM dd, yyyy");
if (dateTime != null) {
String dateTimeDisplay = dateTime.format(dateTimeFormat);
System.out.print("\nIt is currently " + dateTimeDisplay + "\n");
}
Related
I'm trying to make a app which includes telling the time of next Thursday. App crashes every time i open that class.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_authorised);
button.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
nextThursday();
}
});
}
void nextThursday(){
String nextThursday = getNext(DayOfWeek.THURSDAY).format(DateTimeFormatter.ofPattern("MMM, dd yyyy", Locale.ENGLISH));
nextThurs.setText(nextThursday);
}
public static LocalDate getNext(DayOfWeek dayOfWeek) {
// get the reference day for the word "next" (that is the current day)
LocalDate today = LocalDate.now();
// start with tomorrow
LocalDate next = today.plusDays(1);
// as long as the desired day of week is not reached
while (next.getDayOfWeek() != dayOfWeek) {
// add one day and try again
next = next.plusDays(1);
}
// then return the result
return next;
}
}
Is anyone able to help?
This answer uses java.time, which is the datetime API to be used since the Joda Time project stopped further development.
It basically uses an algorithm that may be realizable in Joda Time, too, but I don't know exactly if and how, so I show you a way in java.time.
Define a method that returns the date of the next given day of week:
public static LocalDate getNext(DayOfWeek dayOfWeek) {
// get the reference day for the word "next" (that is the current day)
LocalDate today = LocalDate.now();
// start with tomorrow
LocalDate next = today.plusDays(1);
// as long as the desired day of week is not reached
while (next.getDayOfWeek() != dayOfWeek) {
// add one day and try again
next = next.plusDays(1);
}
// then return the result
return next;
}
and use it in a main() just to print it out:
public static void main(String[] args) {
System.out.println("Next Thursday is " +
getNext(DayOfWeek.THURSDAY)
.format(DateTimeFormatter.ofPattern("MMM, dd yyyy", Locale.ENGLISH)));
}
which results in the output when executed Friday, 15th of May 2020:
Next Thursday is May, 21 2020
Of course, the format is just an example and can easily be adjusted according to your needs.
It's quite simple using a predefined TemporalAdjuster:
LocalDate date = LocalDate.now()
.with(TemporalAdjusters.next(DayOfWeek.THURSDAY));
This is natively supported since Java 8 or Android API level 26. To target previous API levels, use the ThreeTen Android Backport.
Joda Time is in maintenance mode, and they're suggesting that you use java.time instead.
Deleted all code in that activity. Still crashed. Error was not in the code. Something else got messed up instead.
So I read through a few different threads but none of them seem to directly address how I fix my issue. I'm trying to create a Calendar (Gregorian) and then use the .complete() method so that in my classes using this (Paycheck) class I can find relative dates and create new Calendar(s) from those dates to determine wages payed and wages owed. However, it's telling me that .complete() .computeTime() and .computeFields() are all not visible.
From what I've read, this seems to be because they are protected methods and even though I import the java.util for them, I can't access them because that class is not in my package. How do I get this so that I can call the .complete() method?
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.TimeZone;
public class Paycheck {
//fields
protected double grossAmount;
protected Calendar paymentDate;
protected Calendar payPeriodStart;
public Paycheck(double grossAmount, int iYear, int iMonth, int iDay, int sYear, int sMonth, int sDay) {
this.grossAmount = grossAmount;
TimeZone tz1 = TimeZone.getTimeZone("America/Chicago");
this.paymentDate = new GregorianCalendar(iYear, iMonth, iDay);
this.paymentDate.setTimeZone(tz1);
this.paymentDate.complete(); //says "method not visible"
this.payPeriodStart = new GregorianCalendar(sYear, sMonth, sDay);
this.payPeriodStart.setTimeZone(tz1);
}
In a comment you wrote:
I don't care about the actual time, I just want it to give me the date so I can determine the dayofweek (important based on various state laws).
That is very easy to do, and don't need any call to internal methods.
Calendar cal = new GregorianCalendar(2016, Calendar.SEPTEMBER, 22);
cal.setTimeZone(TimeZone.getTimeZone("America/Chicago"));
System.out.println("Day of week (1=Sun, ..., 7=Sat): " + cal.get(Calendar.DAY_OF_WEEK));
Output
Day of week (1=Sun, ..., 7=Sat): 5
Output is 5 because today is Thu 9/22/2016, and that's the date that was given.
Let's compare the typing effort:
this.paymentDate = new GregorianCalendar(iYear, iMonth, iDay);
this.paymentDate.complete(); // Why do you need to call this one?
vs the code having the same effect
this.paymentDate = new GregorianCalendar(iYear, iMonth, iDay, 0, 0, 0);
// constructor taking extra hours, minutes, seconds ----------^
So why do you try the almost-impossible of calling a protected method?
In some cases, very limited in number, one really needs to call a protected/private method and this may be possible. Exemplifying:
Class<GregorianCalendar> clazz=GregorianCalendar.class;
Method completeMethod = clazz.getDeclaredMethod("complete");
// this does the trick if it doesn't throw security exceptions
completeMethod.setAccessible(true);
completeMethod.invoke(this.paymentDate);
See the Javadoc for AccesibleObject.setAccessible, Method being derived from AccessibleObject
Firstly, bear with me – I'm only about a month into Java.
In an exercise, I'm asked to proof (with a test unit) that from a certain year (x) to a certain other year (y) that there are only one day between 31st of December and the 1st of January. They suggest that I should use a for-loop to make it run through all the years in-between our x and y year.
A predefined method called daysTill is already created.
So far, I've come up with this ugly piece of code, which doesn't work:
public void testYearEnd()
{int i;
for(i = 1635; i <=2300; i++);
Date date1 = new Date(i, 31, 12);
Date date2 = new Date(i, 01, 01);
assertEquals(1, date1.daysTill(date2));
}
Can anyone bear to point out exactly where my code is failing on me?
Two problems here: you have a stray ; that's ending your for-statement without a body, making it a no-op, and missing braces around the intended body. (Without the ;, this wouldn't compile as the Date declaration isn't a statement.)
You can also move the declaration of i into the for-statement (you couldn't before because the for-statement ended early due to the ;, so i was undefined for the Date constructors).
The code should be
public void testYearEnd() {
for (int i = 1635; i <= 2300; i++) {
Date date1 = new Date(i, 31, 12);
Date date2 = new Date(i, 01, 01);
assertEquals(1, date1.daysTill(date2));
}
}
I have the following code:
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
TimeZone tz2 = TimeZone.getTimeZone("GMT");
dateFormat.setTimeZone(tz2);
String aDate = "2012-05-02 23:59:59";
for(int i=0 ; i<1000; i++){
dateFormat.setLenient(false);
ParsePosition p = new ParsePosition(0);
Date date = dateFormat.parse(aDate, p);
java.sql.Date sqlDate = null;
if (p.getIndex() != aDate.length())
throw new RuntimeException("just a test");
}
After testing plenty of times, it was very stranger. Basically, it never be finished completely, it ran into exception very randomly.
You see the code should be correct, but: it ran into exception when maybe i is 500 or i is 799 or i is 988(just take some examples here, means it was not getting happened when i = 0, it actually has finished some circles), the exception may get thrown in either line Date date = dateFormat.parse(aDate, p); or line throw new RuntimeException("just a test");;
Can everybody advice me whats wrong?
SimpleDateFormat.parse() uses an instance variable called calendar to build the date from the string. If two threads try to parse at the same time, the calendar variable will get clobbered and you'll get wrong results.
Making the variable not static won't necessarily help, since two threads could still be using the same controller. A better solution is to either create a new DateFormat object each time you parse a date, or use thread local storage. Better still, use JodaTime which has thread safe parsers.
Also consider the following points while using SDF.
Creating SimpleDateFormat is expensive. Don't use this unless it's done seldom.
OK if you can live with a bit of blocking. Use if formatDate() is not used much.
Fastest option IF you reuse threads (thread pool). Uses more memory than 2. and has higher startup overhead.
For applications both 2. and 3. are viable options. Which is best for your case depends on your use case. Beware of premature optimization. Only do it if you believe this is an issue.
For libraries that would be used by 3rd party I'd use option 3.
Your code just plain works, even after 20 reruns. So let's take a guess at what your real SSCCE might look like:
public static void main(String[] args) {
final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
dateFormat.setLenient(false);
final String aDate = "2012-05-02 23:59:59";
for (int i = 0; i < 2; i++)
new Thread() { public void run() {
for (int i = 0; i < 1000; i++) {
ParsePosition p = new ParsePosition(0);
dateFormat.parse(aDate, p);
if (p.getIndex() != aDate.length())
throw new RuntimeException("just a test");
}
System.out.println("Done");
}}.start();
}
This breaks, more or less the way you describe, and for obvious reasons. Listen to #Bhavik Ambani's advice, he's covering this for you.
p.getIndex() != aDate.length()
This statement is returning true, which means that when you parsed the date you did not consume the entirety of string aDate, mean aDate either has timezone or other information also
I have a list of objects called Activity:
class Activity {
public Date activityDate;
public double amount;
}
I want to iterate through List, group them by date and return a new list . Here's what I currently do:
private List<Activity> groupToList(List<Activity> activityList) {
SimpleDateFormatter sdf = new SimpleDateFormatter("YYYY-MM-DD");
Map<String,Activity> groupMap = new HashMap<String,Activity>();
for (Activity a in activityList) {
String key = sdf.format(a.getActivityDate());
Activity group = groupMap.get(key);
if (group == null) {
group = new Activity();
groupMap.add(key, group);
}
group.setAmount(group.getAmount() + a.getAmount());
}
return new ArrayList<Activity>(groupMap.values());
}
Is it a WTF to use the DateFormatter in this way?
I'm using the DateFormatter because each activityDate could have time information.
I would just use the date object itself as the key. If it it bothers you because the date object is mutable, then use its toString() value. No reason to go making formats.
If the issue is that you want to normalize the date by removing the time component, it would be much better to do that withing the Activity object and remove the time component. If the issue is still further that there are potential time zone issues, I would use JodaTime, but there is no object in the JDK currently that represents a pure date without time, so going with a string isn't outrageous, but it should be hidden behind a method in the Activity object and the fact that it is a date formatted string without a time component should be an implementation detail.
java.util.Date is a quite poor abstraction for your need; it is IMO fair to stick to strings if nothing better is around, HOWEVER Joda-time provides a good datatype for you: DateMidnight or alternatively LocalDate if Activity is strictly timezome-independant.
other than that, the code looks good to me, you might be able to shorten it a bit using an implementation of Multimap, to avoid messy null-checking code. to be honest, it doesn't get much shorter than your solution:
public List<Activity> groupedByDate(List<Activity> input) {
//group by day
final Multimap<DateMidnight, Activity> activityByDay
= Multimaps.index(input, new Function<Activity, DateMidnight>() {
#Override
public DateMidnight apply(Activity from) {
return new DateMidnight(from.activityDate);
}
});
//for each day, sum up amount
List<Activity> ret = Lists.newArrayList();
for (DateMidnight day : activityByDay.keySet()) {
Activity ins = new Activity();
ins.activityDate = day.toDate();
for (Activity activity : activityByDay.get(day)) {
ins.amount+=activity.amount;
}
}
return ret;
}
Why not simply create a HashMap<Date, Activity>() instead of the roundabout way with Strings?
Sorry, I didn't answer the question. The answer is: yes, unless I am an idiot ;)
You could do this using the Date as the key if you used a TreeMap and provided a Comparator that only compared the year, month and day and not the time.
As already mentioned the best solution is to represent your date with day precission. If this is not possible joda is nice library.
If you can ignore daylight saving time then grouping by date can be accomplished much easier. A unix time day is 86 400 s long. The timestamp does ignore leap seconds. (Your timer stops for one second or the leap second is distributed in some way.) All date values were day is equal are the same day:
int msPerDay = 86400 * 1000;
long day = new Date().getTime() / msPerDay
One minor point is to adjust the timezone. For my timezone CET (UTC/GMT +1 hour) the GMT day starts one our later:
new GregorianCalendar(2009, 10, 1, 1, 0).getTime().getTime() / msPerDay) ==
new GregorianCalendar(2009, 10, 2, 0, 59).getTime().getTime() / msPerDay) ==
new Date().getTime() / msPerDay
If the daylight saving time is significant the best way is to use joda. The rules are just to complicated and locale specific to implement.