I'm quite new to visualforce/apex programming and kinda stuck in parsing current time and time functions in apex.
Basically I'm trying to figure out if the current time is within my given time range.
How do I write this in apex language?
public String isWorkhours;
public String getIsWorkhours() {
Datetime current_time = *(get current time)*
Datetime start_time = *(7:00 am)*
Datetime end_time = *(7:00 pm)*
if ((current_time >= start_time) && (current_time <= end_time)) {
isWorkhours= 'yes';
} else {
isWorkhours= 'no';
}
return isWorkhours;
}
First of all - check if you can use Business Hours (standard object) to configure SF instead of writing similar functionality manually. Just check your online help for these.
Example of comparison of 2 datetime objects: http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_classes_businesshours.htm
Secondly - read the reference of Time class. Something like this?
Time start = Time.newInstance(7,0,0,0), stop = Time.newInstance(19,0,0,0);
DateTime now = System.now(); // or DateTime.now();
System.debug(now.time() > start && now.time() < stop);
Related
Using SwiftUI (or Combine) how might I set up a series of one or more events that are triggered by the (system) clock. Examples might include:
Every night at midnight,
On the hour,
Every fifteen minutes on the quarter hour,
Finally, on a slightly different note: On the 29th of February 2020 at 12:15.
An approximation is easily achieved by setting up a timer event that fires every second and then checking the hours/minutes/seconds, etc. but this seems very inefficient for events that may be many hours or days apart.
I'm looking for something that is closely synchronised to the actual system clock and fires off a single event at the required time rather than firing loads of events and having each one ask "Are we there yet?".
I would suggest the following:
DispatchQueue.global(qos: .background).async {
let isoDate = "2020-01-13T16:58:30+0000"
let dateFormatter = ISO8601DateFormatter()
let date = dateFormatter.date(from:isoDate)!
let t = Timer(fire: date, interval: 2, repeats: true) { timer in
print("fired")
}
let runLoop = RunLoop.current
runLoop.add(t, forMode: .default)
runLoop.run()
}
string to date conversion I used this answer to format the time correctly.
The example is in GMT.
documentation apple you can look up timer tolerance which can be adjusted if you need the timer to be very accurate.
interval is in seconds so this solution won't get more accurate than seconds
You might want to enable the Background Modes capability to go for the very long running timers. Never done that so I can't help here.
All your examples should work. I hope this helps!
I had to implement this feature too using Combine / SwiftUI : a Timer that would execute at start then every day, hour or minutes (for testing), here is my solution if it can be useful or improved :)
class PeriodicPublisher {
var periodicFormat: PeriodicFormat = .daily
init(_ format: PeriodicFormat = .daily) {
self.periodicFormat = format
}
// Must have an equatable for removeDuplicate
struct OutputDate: Equatable {
let compared: String
let original: String
init(_ comparedDatePart: String, _ originalDate: String) {
self.compared = comparedDatePart
self.original = originalDate
}
static func ==(lhs: OutputDate, rhs: OutputDate) -> Bool {
return lhs.compared == rhs.compared
}
}
enum PeriodicFormat {
case daily
case hourly
case minutely
func toComparableDate() -> String {
switch self {
case .daily:
return "yyyy-MM-dd"
case .hourly:
return "HH"
case .minutely:
return "mm"
}
}
}
func getPublisher() -> AnyPublisher<OutputDate, Never> {
let compareDateFormatter = DateFormatter()
compareDateFormatter.dateFormat = self.periodicFormat.toComparableDate()
let originalTimerDateFormatter = DateFormatter()
originalTimerDateFormatter.dateFormat = "yyyy-MM-dd HH:mm"
var nowDate: Just<OutputDate> {
let comparedDate = compareDateFormatter.string(from: Date())
let originalDate = originalTimerDateFormatter.string(from: Date())
return Just(OutputDate(comparedDate, originalDate))
}
let timerDate = Timer.publish(every: 2.0, tolerance: 1.0, on: .main, in: .default, options: nil)
.autoconnect()
.map { dateString -> OutputDate in
return OutputDate(compareDateFormatter.string(from: dateString), originalTimerDateFormatter.string(from: dateString))
}
.eraseToAnyPublisher()
return Publishers.Merge(nowDate, timerDate)
.map { $0 }
.removeDuplicates()
.eraseToAnyPublisher()
}
}
How does it work ?
Every 2 seconds the scheduler issue current date (with Timer.publish()), this date is used to create a "OutputDate" holding two properties : one "comparable" part used to compare if something has changed and one "original" part so it can be useful for the consumer.
Comparable property is Timer's date formatted with toComparableDate given the provided configuration (.daily, .hourly, .minutely). Using "removeDuplicates" on this property allow to publish "OutputDate" only when this value changes. Every day or hour or minute.
Publishers.Merge is used to publish a value immediately after instantiation, otherwise nothing happens before the first Timer.publish(every). Here 2 seconds.
How to use it ?
You would use it with Combine like this :
PeriodicPublisher(.daily).getPublisher().sink { date in
print("Day has changed \(date.original)")
}
A similar question to a previous one I asked, but the difference being that this not for direct rendering from an underlying field - it's instead part of a some SSJS.
This is for a view column which displays the result of a SSJS function, which returns HTML that gets rendered. This HTML includes a date from a DateTime field, which gets converted to text using #Text. The problem I have with this is, #Text converts dates using the locale settings of the server, not the browser.
Is there an alternative to #Text(dateValue,"D0S0") that's browser locale aware?
The most "XPagey" way to do this is to use a date/time converter. For example (using a stand-in for the computed value):
<xp:viewColumn columnName="">
<xp:this.value><![CDATA[#{javascript:
new java.util.Date()
}]]></xp:this.value>
<xp:this.converter>
<xp:convertDateTime type="both"/>
</xp:this.converter>
</xp:viewColumn>
That "convertDateTime", with its built-in formats, will respect the browser's provided locale. If you set the option in the Xsp Properties to use the browser's time zone and "Round trip", it should also respect the user's time zone.
I've managed to get round this by using DateFormat.getDateInstance. The only problem with this is it doesn't return a short date in the same format as the XPage date converter (no leading zeros and a 2-figure year). I've got round this though with some fiddling around with the string after.
Here's the full function:
function returnLocalShortDate(ndtDate) {
// Receives NotesDateTime object, Java date or string; returns localised date string in XPages short date format
importPackage(java.text);
if (#IsText(ndtDate)) { // string
var jsDate = #TextToTime(ndtDate);
} else if (ndtDate instanceof Date) { // Java date
var jsDate:Date = ndtDate;
} else if (#IsTime(ndtDate)) { // Notes date/time
var jsDate:Date = ndtDate[0].toJavaDate();
} else {
return("");
}
var strDate:String = java.text.DateFormat.getDateInstance(DateFormat.SHORT, context.getLocale()).format(jsDate);
var strYear = jsDate.getFullYear();
var strDateArray = strDate.split("/");
strDate = ('0' + strDateArray[0]).slice(-2) + '/' + ('0' + strDateArray[1]).slice(-2) + '/' + strYear;
return(strDate);
}
Actually, if you know the format you want, rather than what the user might want via their browser settings, you should use the SimpleDateFormatter class. You can supply the format in accordance with whatever pattern you want from the javadocs for that class. If you supply the NotesDocument object and the field name, this returns the date in dd-MMM-yyyy format.
function getFormattedDate ( doc:NotesDocument, fieldName:String ) {
importPackage(java.text);
var dateFormatter:java.text.SimpleDateFormat = new SimpleDateFormat("dd-MMM-yyyy");
var d:Date = new Date(#Today());
if ( doc.hasItem (fieldName) ) {
var valueVector:java.util.Vector = doc.getItemValueDateTimeArray(fieldName);
var iterator = valueVector.iterator();
while (iterator.hasNext()) {
var itemvalue = iterator.next();
if ((typeof(itemvalue)).endsWith("DateTime")) {
d = new Date(itemvalue.toJavaDate());
return dateFormatter.format(d);
}
}
} else {
return fieldName + " is not on the document"
}
}
I owe credit to Declan Lynch's blog entry on date formatting, which takes a little debugging because SSJS returns the date value as an Vector now.
WinRT uses the DateTimeFormatter class to turn timestamps into human-readable dates. In C++CX, you'll pass it a DateTime instance, which contains a timestamp in UTC time, and let it work its magic.
However, I have an application that consumes timestamps in local time. I'd like to format them and show them to my users, but if I pass the timestamp as is, the DateTimeFormatter will assume that it's UTC and will try to convert it to local time again, resulting in incorrect times.
How can I display local time with WinRT? Is there a way to turn back local time into UTC time?
The timestamps are generated from the machine that consumes them, so there is no risk of timezone confusion. It would also be technically feasible to produce UTC timestamps instead, but this would be rather inconvenient and I'd like to fall back to that only if it's the only way.
Thankfully, FileTimeToSystemTime, TzSpecificLocalTimeToSystemTime and SystemTimeToFileTime are all available to Windows store apps. With that, it's possible to create a function to change local back to UTC.
uint64 LocalTimeToUtcTime(uint64 local)
{
LARGE_INTEGER largeTime;
largeTime.QuadPart = local;
FILETIME intermediate;
intermediate.dwHighDateTime = largeTime.HighPart;
intermediate.dwLowDateTime = largeTime.LowPart;
SYSTEMTIME systemLocal, systemUtc;
if (!FileTimeToSystemTime(&intermediate, &systemLocal))
{
// handle error
}
if (!TzSpecificLocalTimeToSystemTime(nullptr, &systemLocal, &systemUtc))
{
// handle error
}
if (!SystemTimeToFileTime(&systemUtc, &intermediate))
{
// handle error
}
largeTime.HighPart = intermediate.dwHighDateTime;
largeTime.LowPart = intermediate.dwLowDateTime;
return largeTime.QuadPart;
}
You can use the Windows::Globalization::Calendar class to work with local time, or with time in any time zone.
The Calendar defaults to the local time zone if you don't explicitly set one. You can then use GetDateTime() to retrieve a Windows::Foundation::DateTime instance that can be used with DateTimeFormatter.
Calendar^ cal = ref new Calendar();
cal->SetToMin();
cal->Year = 2014;
cal->Month = 7;
cal->Day = 14;
cal->Hour = 12;
cal->Minute = 34;
cal->Second = 56;
DateTime dt = cal->GetDateTime();
DateTimeFormatter^ dtf = ref new DateTimeFormatter("shortdate shorttime");
String^ result = dtf->Format(dt);
Logger::WriteMessage(result->Data());
I have a standard ISO8601 date string:
2004-02-12T15:19:21+00:00
I want to know if this date is older than 10 minutes ago in Flex. So basically:
if ("2004-02-12T15:19:21+00:00" > current_time - 10mins) {
// do whatever
}
What would the syntax be in Flex? I'm basically stuck at trying to convert the string into a Flex Date Object without parsing it character by character.
If you don;t care about the timezone i.e. the date string is in the same timezone as where you are running the application then this should work.
var date:Date = DateFormatter.parseDateString("2004-02-12T15:19:21+00:00");
var now:Date = new Date();
var tenMinAgo:Number = now.time - 1000*60*10;
if (date.time < tenMinAgo) {
trace("More than 10 min ago");
}
The ASP.NET calendar always displays 6 weeks of dates in a 7x6 grid. My problem is that the first day of the target month does not necessarily appear in the first row... in some cases, the entire first row displays dates from the previous month. In other cases, the entire last row displays dates from the next row.
Is there a reliable way to query the calendar object to determine the 42-day range that would be rendered for a specific month/year?
For example, consider June 2008 and Feb 2009:
Notice that the first week contains ONLY dates from prior month http://img371.imageshack.us/img371/2290/datesmq5.png
I assume that the calendar tries to avoid bunching all of the "other month" dates at either the top or bottom of the grid, and therefore puts the first of the target month on the 2nd row. I am looking for an easy way to determine that the displayed range for June 2008 is May 25 - July 5, for instance.
Looking at the public members exposed by the ASP.NET Calendar control I do not believe that this information is something that you can just get from the calendar control.
You have a few options as "workarounds" to this though, although not nice....but they would work.
You could manually calculate the first week values
You can handle the "day render" event to handle the binding of the individual days, and record min/max values.
Granted neither is elegant, but AFAIK it is the only real option
Edit
After discussion in the comments, another option is a modified version of my second option above. Basically the first time Day Render is called, get the block of data for the next 42 days, then you can simply search the list for the proper day value to display on future calls to DayRender, avoiding a DB hit for each day. Doing this is another "non-elegant" solution, but it works, and reduces a bit of load on the DB, but introduces some overhead on the application side.
It will be important here to define well structured page level properties to hold the items during the binding events, but to ensure that if a month changed, etc that it wasn't loaded incorrectly etc.
I wrote a couple of methods to help with this. Just pass in Calendar.VisibleDate:
public static DateTime GetFirstDateOfMonth(DateTime date)
{
return new DateTime(date.Year, date.Month, 1);
}
public static DateTime GetFirstDisplayedDate(DateTime date)
{
date = GetFirstDateOfMonth(date);
return date.DayOfWeek == DayOfWeek.Sunday ? date.AddDays(-7) : date.AddDays((int)date.DayOfWeek * -1);
}
public static List<DateTime> GetDisplayedDates(DateTime date)
{
date = GetFirstDisplayedDate(date);
List<DateTime> dates = new List<DateTime>();
for (int i = 0; i < 42; i++)
{
dates.Add(date.AddDays(i));
}
return dates;
}
I've just been looking into this myself, and got directed to here. I'm personally tempted to go with option two, because the alternative is messy. Ronnie's version is nice, but unfortunately doesn't take into account cultures with different FirstDayOfWeeks.
Using Reflector, we can see how it's done internally:
...
DateTime visibleDate = this.EffectiveVisibleDate();
DateTime firstDay = this.FirstCalendarDay(visibleDate);
...
private System.Globalization.Calendar threadCalendar =
DateTimeFormatInfo.CurrentInfo.Calendar;
private DateTime EffectiveVisibleDate()
{
DateTime visibleDate = this.VisibleDate;
if (visibleDate.Equals(DateTime.MinValue))
{
visibleDate = this.TodaysDate;
}
if (this.IsMinSupportedYearMonth(visibleDate))
{
return this.minSupportedDate;
}
return this.threadCalendar.AddDays(visibleDate,
-(this.threadCalendar.GetDayOfMonth(visibleDate) - 1));
}
private DateTime FirstCalendarDay(DateTime visibleDate)
{
DateTime date = visibleDate;
if (this.IsMinSupportedYearMonth(date))
{
return date;
}
int num = ((int)
this.threadCalendar.GetDayOfWeek(date)) - this.NumericFirstDayOfWeek();
if (num <= 0)
{
num += 7;
}
return this.threadCalendar.AddDays(date, -num);
}
private int NumericFirstDayOfWeek()
{
if (this.FirstDayOfWeek != FirstDayOfWeek.Default)
{
return (int) this.FirstDayOfWeek;
}
return (int) DateTimeFormatInfo.CurrentInfo.FirstDayOfWeek;
}
private bool IsMinSupportedYearMonth(DateTime date)
{
return this.IsTheSameYearMonth(this.minSupportedDate, date);
}
private bool IsTheSameYearMonth(DateTime date1, DateTime date2)
{
return (((this.threadCalendar.GetEra(date1) ==
this.threadCalendar.GetEra(date2)) &&
(this.threadCalendar.GetYear(date1) ==
this.threadCalendar.GetYear(date2))) &&
(this.threadCalendar.GetMonth(date1) ==
this.threadCalendar.GetMonth(date2)));
}
Sadly, the functionality is already there, we just can't get at it!
Mitchel,
Worked perfectly, thank you.
Started with a public variable
bool m_FirstDay = false
in the day_render function
if(m_FirstDay == false)
{
DateTime firstDate;
DateTime lastDate;
firstDate = e.Day.Date;
lastDate = firstDate.AddDays(41);
m_FirstDay = true;
}
I then had the visible date range of the asp.net calendar control. Thanks again.
see this one.
How to Remove the Last Week Of a Calendar