One part of my assignment requires me to use gregorian calendar in the student class.
Every student has a unique studentNumber (int), name (String), **
dateRegistered (GregorianCalendar)
** , id (String) and courseEnrolled (CourseOffering).
import java.util.Calendar;
import java.util.GregorianCalendar;
public abstract class Student
{
private int studentNumber;
private String name;
private String id;
private CourseOffering courseEnrolled;
private GregorianCalendar startDate = new GregorianCalendar();
public Student( int studentNumber, String name, String id, CourseOffering courseEnrolled){
this.studentNumber = studentNumber;
this.name = name;
this.id = id;
this.courseEnrolled = courseEnrolled;
}
public int getStudentNumber(){
return studentNumber;
}
public String toString(){
return String.format("%08d", studentNumber) + " " + name + " " + id;
}
}
I wasn't taught on how to use the calendar in school yet, but this came up for the assignment.
"The constructor that does all the necessary initializations given all necessary values including the day (int), month (int) and year (int) of the registration date "
How do i put the day month year in the constructor ? Help guys :(
tl;dr
LocalDate.of( 2018 , 1 , 23 ) // January 23, 2018.
Use java.time classes instead. Unlike the legacy classes, these modern classes use sane numbering:
2018 is year 2018.
1-12 for January-December.
1-7 for Monday-Sunday.
The java.time classes use static factory methods rather than new constructor calls.
ZonedDateTime
The GregorianCalendar class is now obsolete (good riddance). Replaced by ZonedDateTime.
ZonedDateTime zdt =
ZonedDateTime.of(
LocalDate.of( 2018 , Month.JANUARY , 23 ) ,
LocalTime.of( 18 , 30 ) ,
ZoneId.of( "Africa/Tunis" )
)
;
zdt.toString(): 2018-01-23T18:30+01:00[Africa/Tunis]
LocalDate
The LocalDate class represents a date-only value without time-of-day and without time zone.
A time zone is crucial in determining a date. For any given moment, the date varies around the globe by zone. For example, a few minutes after midnight in Paris France is a new day while still “yesterday” in Montréal Québec.
If no time zone is specified, the JVM implicitly applies its current default time zone. That default may change at any moment, so your results may vary. Better to specify your desired/expected time zone explicitly as an argument.
Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "America/Montreal" ) ;
LocalDate today = LocalDate.now( z ) ;
If you want to use the JVM’s current default time zone, ask for it and pass as an argument. If omitted, the JVM’s current default is applied implicitly. Better to be explicit, as the default may be changed at any moment during runtime by any code in any thread of any app within the JVM.
ZoneId z = ZoneId.systemDefault() ; // Get JVM’s current default time zone.
Or specify a date. You may set the month by a number, with sane numbering 1-12 for January-December.
LocalDate ld = LocalDate.of( 1986 , 2 , 23 ) ; // Years use sane direct numbering (1986 means year 1986). Months use sane numbering, 1-12 for January-December.
Or, better, use the Month enum objects pre-defined, one for each month of the year. Tip: Use these Month objects throughout your codebase rather than a mere integer number to make your code more self-documenting, ensure valid values, and provide type-safety.
LocalDate ld = LocalDate.of( 1986 , Month.FEBRUARY , 23 ) ;
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android, the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
Related
A couple of years ago I wrote a proof of concept function to date strings to calculate the end date from the string. This never made it to production for a number of reasons but all the functions worked. For example the string
999 years less 1 day from 16 August 2000
should evaluate to 15th August 2999. I wrote this function using the Microsoft Recognizers library (V1.3.2) and it all worked.
var culture = Culture.MapToNearestLanguage("en-gb");
DateTimeOptions dateTimeOptions;
dateTimeOptions = DateTimeOptions.ExtendedTypes;
var results = DateTimeRecognizer.RecognizeDateTime(leaseTermPhrase, culture, dateTimeOptions);
results would return 3 elements derived from the string, a duration of 999 years, a duration of 1 day and a date of 16 August 2000, and using that data I was able to calculate the end date (I made an assumption that any second duration should be taken away from the end date).
I am now revisiting this code as the need for it has come back into scope. I updated the Recognizer packages to the latest version (1.8.2) and now the unit test that tests this particular format of string fails (other string formats still pass).
Upon investigation I find that the results variable now only contains two parts; a duration of 999 years and a Date 0f 15 August 2000. So the new library is parsing '1 day from 16 August 2000' as a single date entity instead of two separate ones (a duration and a date)
Does anyone know if it is possible to get the Recognizer to produce the same results as previously?
I am seeing this issue while using Calendar instance to subtract one hour from time when day light saving ends and we transition to standard time.
here is the code:
Date startTime = new Date();// Gives me Sun Nov 06 01:26:16 EST 2016
Calendar temp;
TimeZone timezone = TimeZone.getDefault(); //Eastern
temp= Calendar.getInstance(timezone);
temp.setTime(startTime);
temp.add(Calendar.HOUR_OF_DAY, -1);
temp.set(Calendar.MILLISECOND, 0);
Date endDate = temp.getTime(); // This is still Sun Nov 06 01:26:16 EST 2016
The result that I expect in endDate is Sun Nov 06 01:26:16 EDT 2016 instead of Sun Nov 06 01:26:16 EST 2016. I am not sure if this is as designed or not. If I subtract 2 hours, then I see it working fine.
Any inputs on this?
Thanks,
SS
Using java.time
You should be using java.time classes rather than the troublesome old date-time classes such as Calendar than are now legacy.
Be sure to read the class doc for ZonedDateTime to understand its choice of how to handle the Daylight Saving Time (DST) cut-overs.
Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as EST or EDT or IST as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "America/New_York" );
// of(int year, int month, int dayOfMonth, int hour, int minute, int second, int nanoOfSecond, ZoneId zone)
ZonedDateTime zdt = ZonedDateTime.of( 2016 , 11 , 6 , 1 , 26 , 16 , 0 , z );
ZonedDateTime zdtOneHourEarlier = zdt.minusHours( 1 );
ZonedDateTime zdtOneHourLater = zdt.plusHours( 1 );
Note the offset-from-UTC in each result.
zdt.toString(): 2016-11-06T01:26:16-04:00[America/New_York]
zdtOneHourEarlier.toString(): 2016-11-06T00:26:16-04:00[America/New_York]
zdtOneHourLater.toString(): 2016-11-06T01:26:16-05:00[America/New_York]
See this code run live at IdeOne.com.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
Where to obtain the java.time classes?
Java SE 8 and SE 9 and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
The ThreeTenABP project adapts ThreeTen-Backport (mentioned above) for Android specifically.
See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
We are using JavaMail API to send calendar entries. But the recipients of Outlook have time zone issues, as meetings show wrong timings. In general our approach is as follows:
First of all we have,
SimpleDateFormat iCalendarDateFormat = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
we then use iCalendarDateFormat.setTimeZone(TimeZone.getTimeZone(receiverTimeZone));
Finally, we use Calendar.getInstance() for start and end to manipulate Calendar fields,
and hence we have Date startDate = startTime.getTime();
Date endDate = endTime.getTime();
When we are about to send request as per icalendar specification we have ,
"DTSTAMP:" + iCalendarDateFormat.format(startDate) + "\n" +
"DTSTART:" + iCalendarDateFormat.format(startDate)+ "\n" "DTEND:" + iCalendarDateFormat.format(endDate)+ "\n"
Is this the correct approach?. Please comment.
Thanks
tl;dr
iCalendar format tracks the date-time separately from its intended time zone. You must juggle both parts appropriately.
Always use java.time classes. Never use legacy classes like Calendar & SimpleDateFormat.
Details
Caveat: I have not used iCalendar data before. So I may be incorrect in my understanding.
Looking at pages 31-33 of the RFC 5545 spec, it seems the authors of that spec assume you always want the date-time to be recorded separately from the time zone.
A moment, a point on the timeline, needs the context of a time zone or offset-from-UTC. For example, "noon on the 23rd of January next year, 2021" is not a moment. We do not know if you mean noon in Tokyo Japan, noon in Toulouse France, or noon in Toledo Ohio US — all very different moments, several hours apart.
To provide the context of an offset, a date and time must be accompanied by a number of hours-minutes-seconds such as 08:00. For an offset of zero hours-minutes-seconds, use +00:00.
2021-01-23T12:00:00+00:00
As an abbreviation of an offset of zero, +00:00, the letter Z can be used, pronounced “Zulu”. For example:
2021-01-23T12:00:00Z
But, strangely, the iCalendar spec wants to track the date and the time-of-day separate from the time zone. So this:
2021-01-23T12:00:00
…and a time zone field elsewhere:
America/New_York
And the iCalendar spec opts for the harder-to-read “basic” variation allowed by ISO 8601, which minimizes the use of delimiters. So this:
20210123T120000
For such a string, we must parse as a LocalDateTime. This class represents a date with a time-of-day but lacking any time zone or offset-from-UTC.
DateTimeFormatter f = dateTimeFormatter.ofPattern( "uuuuMMdd'T'HHmmss" ) ;
String input = "20210123T120000" ; // “Basic” variation of ISO 8601 format.
LocalDateTime ldt = LocalDateTime.parse( input , f ) ;
To determine a moment, we must apply a time zone. I assume iCalendar uses proper time zone names (Continent/Region format) and not the 2-4 letter pseudo-zones such as PST, CST, IST, and so on.
String zoneName = receiverTimeZone ; // Variable name taken from your code example, though you neglected to show its origins.
ZoneId z = ZoneId.of( zoneName ) ;
Apply the zone to get a ZonedDateTime, a moment, a point on the timeline.
ZonedDateTime zdt = ldt.atZone( z ) ;
Going the other direction, let's start with the current moment.
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime now = ZonedDateTime.now( z ) ;
And generate string values for iCalendar.
DateTimeFormatter f = dateTimeFormatter.ofPattern( "uuuuMMdd'T'HHmmss" ) ;
String iCal_DateTime = now.format( f ) ;
String iCal_ZoneName = now.getZone().toString() ;
Never use the terrible legacy date-time classes bundled with the earliest versions of Java: Calendar, GregorianCalendar, java.util.Date, SimpleDateFormat, and so on. These were supplanted years ago by the modern java.time classes defined in JSR 310.
Hard to tell without seeing the actual content of your iCalendar file, along with the expected start and end datetime with timezone information but you seem to be generating the DTSTART in floating time (datetime with local time). Although your code sample seems to imply that you have access to the recipient's timezone (receiverTimezone), this is a very fragile approach.
Instead, you should use either the datetime with UTC time or the datetime with local time and timezone (where the timezone does not have to be the receiver timezone).
If the event is not recurring, the most simple approach is to use datetime with UTC time.
See https://www.rfc-editor.org/rfc/rfc5545#section-3.3.5 for the definition of each format.
I had same problem, for which I struggle lot. So below are my findings:
Outlook works smoothly with UTC Timezone. If we set date & time with UTC Timezone then outlook automatically converts this UTC Time into user corresponding Timezone. We will have to use 'Instant' object for DTSTART:, DTEND: and for DTSTAMP(Optional but recommended) also.
Quick Test just use "DTSTART:"+Instant.now() in ical String.
And in Java 8 for getting UTC Time java time API provides Instant.now() through which you can get your system time in UTC format. Java 8 also provides method like
a. Instant.ofEpochMilli() - This returns Instant which can directly use in ical Sting.
b. new Date().toInstant() Which returns UTC Instant object.
There are few scenarios where input date and time sources are different:
If you are fetching Date and Time from database then in this case database is not storing Timezone its only saving Date & Time. So first convert the Date & Time in that Timezone in which it was saved in database, in my case I was storing Date & Time after converting in 'EST' Timezone and Date value was of EST but time zone was not there in DB. So while fetching Date & Time value from DB I have appended Timezone in the Date value and then further converted to EPOC time using below method
public static long getEpocTimeWithTimezone(Date date) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
DateTimeFormatter dateTimePattern = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime dateTime = LocalDateTime.parse(simpleDateFormat.format(date), dateTimePattern);
long epochInMilliSeconds = dateTime.atZone(ZoneId.of("America/New_York")).toEpochSecond() * 1000;
return epochInMilliSeconds;
}
Then Just Use as below code for ical String:
Instant startDt = Instant.ofEpochMilli(getEpocTimeWithTimezone(//pass your date here
)).truncatedTo(ChronoUnit.MINUTES);
Now set this Instant object(startDt) directly to "DTSTART:":
"DTSTART:"+startDt+"....then in same fashion "DTEND:" also.
In second scenario you have Date with Timezone (make sure after conversion you did not loses your actual Timezone, Like in 1st scenario after saving Date in DB we actually lost Timezone but it was showing Timezone IST that was dummy so be careful about this)
So in this case just assume myDateObject is Date object. So just get the Instant (which
will be in UTC) object from myDateObject by using toInstant() of Date class.
Instant startDt = myDateObject.toInstant().truncatedTo(ChronoUnit.MINUTES);
I am using .truncatedTo(ChronoUnit.MINUTES); because if we will not use this then
we might get some extra min or second in Meeting invite Time section.
So the final String for outlook mail should be some like:
.
.
.
"BEGIN:VEVENT\n"+
"DTSTART:"+startDt+"\n"+
"DTEND:"+endDt+"\n"+
.
.
.
VVI Note: Since Z is representation of UTC time zone, So just adding Z in the last of Time will not be UTC zoned Time, You will have to convert the Date & Time then only accurate time will come on Outlook. For verifying your Time is in UTC format or not just save the .ics attached file (which you got in Email) in local and check Date & Time are coming as DTSTART:2020-05-15T13:57:00Z or not If not then you are not converting the Date correctly in UTC.
What is the best way to add an expiry date in CakePHP?
I've got an "expiry date" column in my database, I want to add 1 month to the current date, and store this. At the moment, I'm just using strings and plain PHP date functions to create a new date string to save:
$date = date("Y-m-d");
$date = strtotime(date("Y-m-d", strtotime($date)) . " +31 days");
$this->data['Access']['expires'] = $date;
Is there a "more CakePHP" way or efficient/performance wise?
Performance wise we're most probably talking about micro optimizations at best, so that probably shouldn't be your main concern. However, all the back and forth that you're doing there doesn't make much sense, a single call to strtotime() is all you need, ie
$this->data['Access']['expires'] = strtotime('+31 days');
This will result in a timestamp of "now + 31 days".
The Cake-ish way would be to use the CakeTime class, for example CakeTime::fromString(), like
App::uses('CakeTime', 'Utility');
$this->data['Access']['expires'] = CakeTime::fromString('+31 days');
When passing a string (it also accepts integers and \DateTime instances), this is basically just a wrapper for strtotime(), and an additional mechanism that incorporates the timezone set for your application, so while this will be a little bit slower of course, it might still be wise to use it.
See also
Cookbook > Core Libraries > Utilities > CakeTime
Better that adding 31 days is better to use 1 months this will add 30 or 31 days depending on which month will be the current date
$dateAfterOneMonth = date('Y-m-d H:i:s', CakeTime::fromString('+1 months'))
Does anyone knows why the control does not support higher values like 12/31/9999? I am looking for the particular reason for this.
From the DateTimePicker.cs source code file, as visible at the ReferenceSource site:
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
public static readonly DateTime MaxDateTime = new DateTime(9998, 12, 31);
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
public static readonly DateTime MinDateTime = new DateTime(1753, 1, 1);
These limits are checked in the Value property setter before it pinvokes the native control to set the date.
Not 100% sure where these limits came from. They do follow the common pattern, a programmer taking a shortcut to avoid dealing with an awkward problem. Some common examples:
COM dates can't go lower than 1900. That was a shortcut taken by a Lotus programmer, working on the once dominant spreadsheet program called "123". He didn't deal with the year 1900 not being a leap year. Microsoft had to copy the bug in Excel to keep it compatible with Lotus spreadsheets.
The year 1753, as used in DateTimePicker.MinDateTime was a shortcut taken by a Sybase programmer, the company that started SQL Server. That's the year that England switched from the Julian to the Gregorian calender. Which caused 15 days to get lost, the amount by which Julian dates drifted by not properly handling leap years. Not having to deal with invalid dates was obviously desirable. Putting that limit into DTP avoids data-binding problems.
DateTime.MinDate being the year 0 is a shortcut for not having to deal with negative DateTime.Tick values.
DateTime.MaxDate being the year 10,000 was a shortcut around a problem with TimeSpan.TotalMilliseconds. Which returns a double, a value type that has up to 15 significant digits. Going beyond 10,000 requires more digits.
Which inspires an explanation for the year 9998, there are plenty of icky problems getting close to DateTime.MaxDate. For example, SQL Server conks out at 3 milliseconds before midnight, .NET at 100 nanoseconds before midnight. DateTimePicker uses local time which can cause MaxDate to be exceeded in various timezones throughout the day of December 31st. So the Microsoft programmer did what most any other programmer did before him, he took a shortcut:
public static DateTime MaximumDateTime {
get {
DateTime maxSupportedDateTime = CultureInfo.CurrentCulture.Calendar.MaxSupportedDateTime;
if (maxSupportedDateTime.Year > MaxDateTime.Year)
{
return MaxDateTime;
}
return maxSupportedDateTime;
}
}
This is of course never a real problem, it is not meaningful to handle dates that far into the future. Use the MaximumDateTime property if you need some kind of validity check in your own code.
This is another non-answer, but maybe it'll be useful to someone. Following the WINAPI route in my comment, SYSTEMTIME is limited to dates between 1601 and 30827 because it is based on a FILETIME structure, which stores time as a 64-bit count of 100ns ticks since #1/1/1601#. It further only allows values less than 0x8000000000000000, which results in the year 30827 upper limit.
The .NET DateTimePicker control is based on the WINAPI Date and Time Picker control, so it makes sense that it would have at least these limits. The documentation mentions the switch from the Julian to the Gregorian calendar in 1753, which may explain the #1/1/1753# limit coded into the .NET control.
That may help to explain the lower limit, but still doesn't explain the upper limit. Unless someone from the development team chimes in, the only answer to "why?" may be "because it's hardcoded that way".
{Edit: the justification for the 1601 date for SYSTEMTIME appears to be that it was the previous start of a 400-year cycle in the proleptic Gregorian calendar. Still doesn't help explain #12/31/9998#.}
This isn't a proper answer (though I'm still trying to dig). Looking at the source there is a field defined in the DateTimePicker:
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
public static readonly DateTime MaxDateTime = new DateTime(9998, 12, 31);
In your question you ask why it is "12/31/9998 23:59:59" when in fact it is only "12/31/9998 00:00:00", which is almost more peculiar.
I then searched for usages of this field. It seems to be used only as an absolute bound for the date time picker and nothing else. In fact, the MaximumDateTime property looks like this:
public static DateTime MaximumDateTime
{
get
{
DateTime supportedDateTime = CultureInfo.CurrentCulture.Calendar.MaxSupportedDateTime;
if (supportedDateTime.Year > DateTimePicker.MaxDateTime.Year)
return DateTimePicker.MaxDateTime;
else
return supportedDateTime;
}
}
So the maximum date is actually defined by either the current culture's defined maximum supported date, or the absolute maximum supported by the DateTimePicker, whichever is less in terms of the year part. For the "en-US" culture the maximum supported date is equal to DateTime.MaxValue, so the MaxDateTime field is used insteam.
Again, this isn't meant to answer why the particular value is used, but to give more insight on how it is being used within the DateTimePicker itself.