xamarin SetAlarm on a DateTime - xamarin

I wish to set the alarm so that it sends a notification whenever the alarm is fired. The below code which I have, the alarmDate.Millisecond returns 0 (because it was never set). It should return the correct millis for the alarm to work - I think it takes the milliseconds for UTC - But the time has to be GMT/DST in the UK.
Code:
private void InitBroadcast()
{
// Build the intents
var intent = new Intent(this, typeof(MyReceiver));
var pendingIntent = PendingIntent.GetBroadcast(this, 0, intent, 0);
var alarmManager = (AlarmManager)GetSystemService(AlarmService);
// Build the dates
var currentDate = DateTime.Now;
var alarmDate = new DateTime(currentDate.Year, currentDate.Month, currentDate.Day, 5, 29, 0, DateTimeKind.Local);
// If the alarm time has already past, set the alarm date to tomorrow
if (DateTime.Compare(currentDate, alarmDate) < 0) {
alarmDate.AddDays(1);
}
alarmManager.SetRepeating(AlarmType.RtcWakeup, alarmDate.Millisecond, millisInADay, pendingIntent);
textView.SetText(string.Format("Alarm set for {0}", alarmDate.ToString()), TextView.BufferType.Normal);
}

Check the docs: https://learn.microsoft.com/en-us/dotnet/api/system.datetime.millisecond?view=netframework-4.7.2#System_DateTime_Millisecond
The milliseconds component, expressed as a value between 0 and 999.
So alarmDate.Millisecond does not return 0 because it was never set, it returns 0 because it was set to zero then you created the DateTime object with alarmDate = new DateTime(currentDate.Year, currentDate.Month, currentDate.Day, 5, 29, 0, DateTimeKind.Local);
See: https://learn.microsoft.com/en-us/dotnet/api/system.datetime.-ctor?view=netframework-4.7.2#System_DateTime__ctor_System_Int32_System_Int32_System_Int32_System_Int32_System_Int32_System_Int32_System_DateTimeKind_
You are setting the time to the current date at 5:29 am ( with 0 for the seconds, so the 0 for milliseconds is implied).
alarmDate.Ticks would give you the umber of "Ticks" (1/10,000 of a millisecond) that have elapsed since the beginning of the twenty-first century. But do keep in mind what SushiHangover said in the so link in his comment
Android's AlarmManager is based upon Android/Linux Epoch milliseconds
not .NET DateTime ticks. Epoch milliseconds are the number of milliseconds that have elapsed since January 1, 1970 at 00:00:00 GMT (1970-01-01 00:00:00 GMT).
So instead of passing in alarmDate.Millisecond to the alarmManager.SetRepeating method, use a TimeSpan between the current time and Jan 1, 1970 midnight GMT to get the epoch milliseconds and pass that in instead, e.g.:
var epochMs = (alarmDate - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds;
alarmManager.SetRepeating(AlarmType.RtcWakeup, (Int64)epochMs, millisInADay, pendingIntent);

Related

ZonedDateTime would use same timezone of winter when summer daylight saving?

ZonedDateTime zdt = ZonedDateTime.of(2015, 10, 18, 0, 30, 0, 0,
ZoneId.of("America/Sao_Paulo"));
System.out.println(zdt); // 2015-10-18T01:30-02:00[America/Sao_Paulo]
You can see the hour is 1 while we set the hour as 0, and timezone is UTC-02:00 while daylight saving timezone should be UTC-03:00.
But here is a different example:
ZonedDateTime zdt = ZonedDateTime.of(2015, 10, 18, 0, 30, 0, 0,
ZoneId.of("America/Los_Angeles"));
System.out.println(zdt); //2015-10-18T00:30-07:00[America/Los_Angeles]
You can see the daylight saving timezone is UTC-07:00 and the hour is 0 as we set.
Why are they different?
This happens because the time you picked falls in the gap between midnight and 01:00 on the night when Brazil switches to summer time. That time is actually impossible and so you get the behavior described in the documentation:
In the case of a gap, when clocks jump forward, there is no valid offset. Instead, the local date-time is adjusted to be later by the length of the gap. For a typical one hour daylight savings change, the local date-time will be moved one hour later into the offset typically corresponding to "summer".
You can observe the same behavior in Los_Angeles zone by picking a time between 02:00 and 03:00 on the corresponding night in March:
zdt = ZonedDateTime.of(2015, 3, 8, 2, 30, 0, 0,
ZoneId.of("America/Los_Angeles"));
System.out.println(zdt);
As already explained in #Misha's answer, it happens due to Daylight Saving Time rules.
In São Paulo, DST starts at the midnight of 2015-10-18: the clocks move forward 1 hour, so it "jumps" from 23:59:59 to 01:00:00. There's a gap between 00:00:00 and 00:59:59, so the time 00:30 is adjusted accordingly.
You can check if the date and time are valid for the timezone using the ZoneRules and ZoneOffsetTransition classes:
ZoneId sp = ZoneId.of("America/Sao_Paulo");
ZoneRules rules = sp.getRules();
// check if 2015-10-18 00:30 is valid for this timezone
LocalDateTime dt = LocalDateTime.of(2015, 10, 18, 0, 30);
List<ZoneOffset> validOffsets = rules.getValidOffsets(dt);
System.out.println(validOffsets.size()); // size is zero, no valid offsets at 00:30
The getValidOffsets method returns all the valid offsets for the specified date/time. If the list is empty, it means the date/time doesn't "exist" in that timezone (usually because of DST the clocks jump forward).
When the date/time exists in a timezone, an offset is returned:
ZoneId la = ZoneId.of("America/Los_Angeles");
rules = la.getRules();
validOffsets = rules.getValidOffsets(dt);
System.out.println(validOffsets.size()); // 1 - date/time valid for this timezone
System.out.println(validOffsets.get(0)); // -07:00
For Los_Angeles timezone, 1 valid offset is returned: -07:00.
PS: Offset changes usually occur due to DST, but that's not always the case. DST and offsets are defined by governments and laws, and they can change at anytime. So, a gap in the valid offset can also mean that such change occured (some politician decided to change the standard offset of the country, so the gap might not necessarily be related to DST).
You can also check when the change occurs, and what's the offset before and after it:
ZoneId sp = ZoneId.of("America/Sao_Paulo");
ZoneRules rules = sp.getRules();
// get the previous transition (the last one that occurred before 2015-10-18 00:30 in Sao_Paulo timezone
ZoneOffsetTransition t = rules.previousTransition(dt.atZone(sp).toInstant());
System.out.println(t);
The output is:
Transition[Gap at 2015-10-18T00:00-03:00 to -02:00]
It means that there's a gap (clocks moving forward) at 2015-10-18T00:00, and the offset will change from -03:00 to -02:00 (so, clock moves 1 hour forward).
You can also get all these info separately:
System.out.println(t.getDateTimeBefore() + " -> " + t.getDateTimeAfter());
System.out.println(t.getOffsetBefore() + " -> " + t.getOffsetAfter());
The output is:
2015-10-18T00:00 -> 2015-10-18T01:00
-03:00 -> -02:00
It shows that, at 00:00 the clock moves directly to 01:00 (so 00:30 can't exist). In the second line, the offsets before and after the change.
If you check the transitions in Los_Angeles timezone, you'll see that its DST starts and ends at different dates:
ZoneId la = ZoneId.of("America/Los_Angeles");
rules = la.getRules();
// 2015-10-18 00:30 in Los Angeles
Instant instant = dt.atZone(la).toInstant();
System.out.println(rules.previousTransition(instant));
System.out.println(rules.nextTransition(instant));
The output is:
Transition[Gap at 2015-03-08T02:00-08:00 to -07:00]
Transition[Overlap at 2015-11-01T02:00-07:00 to -08:00]
So, in Los_Angeles timezone, DST starts at 2015-03-08 and ends at 2015-11-01. That's why at 2015-10-18, all hours are valid (there's no adjustment as it happens in Sao_Paulo timezone).
Some timezones have transition rules (like "DST starts at the third Sunday of October") instead of just transitions (like "DST starts at this specific date and time"), and you can also use them, if available:
ZoneId sp = ZoneId.of("America/Sao_Paulo");
ZoneRules rules = sp.getRules();
// hardcoded: Sao_Paulo timezone has 2 transition rules, the second one is relative to October
// but you should always check if the list is not empty
ZoneOffsetTransitionRule tr = rules.getTransitionRules().get(1);
// get the transition for year 2015
ZoneOffsetTransition t = tr.createTransition(2015);
// use t the same way as above (the output will be the same)
Another way to check if a date and time is valid for some timezone is to use the ZonedDateTime.ofStrict method, that throws an exception if the date and time is invalid for a timezone:
ZoneId sp = ZoneId.of("America/Sao_Paulo");
ZoneId la = ZoneId.of("America/Los_Angeles");
LocalDateTime dt = LocalDateTime.of(2015, 10, 18, 0, 30);
System.out.println(ZonedDateTime.ofStrict(dt, ZoneOffset.ofHours(-7), la)); // OK
System.out.println(ZonedDateTime.ofStrict(dt, ZoneOffset.ofHours(-3), sp)); // throws java.time.DateTimeException
The first case is OK, because an offset of -7 is valid for Los Angeles, for the given date/time. The second case throws an exception because an offset of -3 is invalid for São Paulo, at the given date/time.

How to convert time::Tm to u64 for JWT expiration date

I'm using the jwt crate and I want to set the expiration date in the Claims struct. The exp field in Registered took a Option<u64>.
I can retrieve the current date and add 1 day to it by doing:
let mut timer = time::now();
timer = timer + Duration::days(1);
but I don't see how to convert this time::Tm to a u64.
The exp field is of "NumericDate" type, which according to RFC 7519 is "number of seconds from 1970-01-01T00:00:00Z UTC until the specified UTC date/time, ignoring leap seconds."
This description is the same as the to_timespec method, which "Convert time to the seconds from January 1, 1970" in the Tm's current timezone*.
Thus:
let mut timer = time::now_utc();
timer = timer + Duration::days(1);
token.claims.reg.exp = Some(timer.to_timespec().sec as u64);
(Note that while time + duration always return UTC time as of v0.1.36, it is arguably a defect that could be fixed in a future. To be forward-compatible, I used now_utc() instead of now().)
(*: to_timespec basically calls gmtime() on POSIX and the POSIX standard ignores leap seconds. On Windows it converts the structure to a FILETIME which again ignores leap seconds. So to_timespec is safe to use if you really care about the 27-second difference.)
If you are using std::time::SystemTime, the same can be obtained using
let mut timer = SystemTime::now();
timer += Duration::from_secs(86400);
token.claims.reg.exp = Some(timer.duration_since(UNIX_EPOCH).unwrap().as_secs());

Converting dates in msg file to match outlook local dates muddle

I am taking the MSG file and changing the date to match the local date in outlook. (same Sent date when you open the message in outlook).
But the times seem to be off 1 hour or many hours. I've dumped out the times to investigate further:-
I'm using Aspose to open the msg file.
c#
1.msg Shows: 05/01/2011 00:46 in outlook 2016. GMT
05/01/2011 00:46:07, Kind = Utc
TimeZone offset = -08:00:00
Actual UTC Time is 05/01/2011 00:46:07
Message date to universal time + timezoneoffset: 04/01/2011 16:46:07
timezoneoffset: -08:00:00
calculated universal msg date: 04/01/2011 16:46:07
output 04/01/2011 08:46 AM
2.msg Shows 20/06/2016 16:25 in outlook 2016. GMT
20/06/2016 16:25:23, Kind = Local
TimeZone offset = 02:00:00
Actual UTC Time is 20/06/2016 15:25:23
Message date to universal time + timezoneoffset: 20/06/2016 17:25:23
timezoneoffset: 02:00:00
calculated universal msg date: 20/06/2016 17:25:23
output 06/20/2016 07:25 PM
any ideas on how to correct this to show same as outlook? I see some times are UTC and some are Local, is there a solution anyone know of?
MailMessage msg = MailMessage.Load(inFile);
MemoryStream ms = new MemoryStream();
Console.WriteLine(msg.Date.ToString() + ", Kind = " + msg.Date.Kind);
Console.WriteLine("TimeZone offset = " + msg.TimeZoneOffset);
Console.WriteLine("Actual UTC Time is " + msg.Date.ToUniversalTime().ToString());
Console.WriteLine("Message date to universal time + timezoneoffset: " + (msg.Date.ToUniversalTime() +
msg.TimeZoneOffset).ToString());
Console.WriteLine("timezoneoffset: " + msg.TimeZoneOffset.ToString());
// do calculation.
TimeZone localZone = TimeZone.CurrentTimeZone;
TimeSpan ts = localZone.GetUtcOffset(msg.Date);
msg.Date = msg.Date + msg.TimeZoneOffset;
Console.WriteLine("calculated universal msg date: " +msg.Date.ToUniversalTime().ToString());
if (msg.Date.Second >= 30) // for rounding up to match outlook
{
// ... Days, hours, minutes, seconds, milliseconds.
TimeSpan span = new TimeSpan(0, 0, 0, 31, 0);
msg.Date = msg.Date + span;
}
MhtMessageFormatter mhtlFormat = new MhtMessageFormatter();
mhtlFormat.DateTimeFormat = "ddd MM/dd/yyyy hh:mm tt";
mhtlFormat.Format(msg);
MhtSaveOptions mhtSaveOptions = new MhtSaveOptions();
mhtSaveOptions.MhtFormatOptions = MhtFormatOptions.None;
mhtSaveOptions.MhtFormatOptions = mhtSaveOptions.MhtFormatOptions | MhtFormatOptions.HideExtraPrintHeader;
Thanks,
Lee.
As assisted on your thread in Aspose.Email forum, we believe your query has already met an answer. If you still find any issue or have confusion, you can inquire further on respective thread.
I work with Aspose as Developer Evangelist.

Set time part of DateTime in ruby

Say I have a datetime object eg DateTime.now. I want to set hours and minutes to 0 (midnight). How can I do that?
Within a Rails environment:
Thanks to ActiveSupport you can use:
DateTime.now.midnight
DateTime.now.beginning_of_day
OR
DateTime.now.change({ hour: 0, min: 0, sec: 0 })
# More concisely
DateTime.now.change({ hour: 0 })
Within a purely Ruby environment:
now = DateTime.now
DateTime.new(now.year, now.month, now.day, 0, 0, 0, now.zone)
OR
now = DateTime.now
DateTime.parse(now.strftime("%Y-%m-%dT00:00:00%z"))
Nevermind, got it. Need to create a new DateTime:
DateTime.new(now.year, now.month, now.day, 0, 0, 0, 0)
Warning: DateTime.now.midnight and DateTime.now.beginning_of_day return the same value (which is the zero hour of the current day - midnight does not return 24:00:00 as you would expect from its name).
So I am adding this as further info for anyone who might use the accepted answer to calculate midnight x days in the future.
For example, a 14 day free trial that should expire at midnight on the 14th day:
DateTime.now.midnight + 14.days
is the morning of the 14th day, which equates to a 13.x day trial (x is the part of the day left over - if now is noon, then it's 13.5 day trial).
You would actually need to do this:
DateTime.now.midnight + 15.days
to get midnight on the 14th day.
For this reason I always prefer to use beginning_of_day, since that is 00:00:00. Using midnight can be misleading/misunderstood.
If you use it often consider install this gem to improve date parse:
https://github.com/mojombo/chronic
require 'chronic'
Chronic.parse('this 0:00')

How do I convert a time to tm struct instead of CTime class

I currently have code that creates a CTime object from a defined value.
#define TIME_VALUE 0x301DDF00 // Aug 1, 1995 # 04:00:00
CTime t = CTime( TIME_VALUE );
This creates the desired date of Aug 1, 1995 04:00:00
I can no longer use CTime so I am trying to use time_t and tm instead. Since the CTime constructor takes in the number of seconds since Jan 1, 1970 and time_t represents the number of seconds since Jan 1, 1970, I tried to use the following code.
#define TIME_VALUE 0x301DDF00 // Aug 1, 1995 # 04:00:00
time_t tmpTime = TIME_VALUE;
struct tm createTime;
if( localtime_s( &createTime, &tmpTime ) == S_OK )
{
// Use createTime
}
createTime ends up as August 1, 0095 04:00:00. How am I supposed to go from the defined value to a time_t and tm successfully?
Thanks in advance.
Sorry. I didn't look at the tm documentation closely enough. The year is the actual year minus 1900 and the month is zero based. I got it now.

Resources