I have an Azure Function that is time triggered. The Azure Function starts at every occasion when it is somewhere 00:00 am (local time). What I would like to achieve is to find the time zone strings (e.g. Europe/London) for the time zones where it is currently 00:00 am when the Azure Function is running.
I.e., I provide an UTC value and it provides me all time zone ids where it is currently 00:00 am local time.
How can I achieve that using NodaTime?
A slightly simpler version than yours, if you always want to check for midnight:
static List<string> GetTimeZonesAtMidnight(Instant instant) =>
// Extension method in NodaTime.Extensions.DateTimeZoneProviderExtensions
DateTimeZoneProviders.Tzdb.GetAllZones()
.Where(zone => instant.InZone(zone).TimeOfDay == LocalTime.Midnight)
.Select(zone => zone.Id)
.ToList();
If you need to check for non-midnight values, pass in a LocalTime:
static List<string> GetTimeZonesAtMidnight(Instant instant, LocalTime timeOfDay) =>
// Extension method in NodaTime.Extensions.DateTimeZoneProviderExtensions
DateTimeZoneProviders.Tzdb.GetAllZones()
.Where(zone => instant.InZone(zone).TimeOfDay == timeOfDay)
.Select(zone => zone.Id)
.ToList();
My first approach (prototype) looks as follows:
using System;
using System.Collections.Generic;
using NodaTime;
namespace TimeZones
{
class Program
{
static void Main(string[] args)
{
Instant utcDateTime = Instant.FromDateTimeUtc(DateTime.UtcNow);
Console.WriteLine(utcDateTime);
List<string> zoneIds = GetTimeZonesWithCondition(utcDateTime, 0, 0);
Console.ReadLine();
}
static List<string> GetTimeZonesWithCondition(Instant utcDateTime, int hourComparison, int minuteComparison)
{
List<string> zoneIdsCheck = new List<string>();
IDateTimeZoneProvider timeZoneProvider = DateTimeZoneProviders.Tzdb;
foreach (var id in timeZoneProvider.Ids)
{
var zone = timeZoneProvider[id];
var zoneDateTime = utcDateTime.InZone(zone);
int hourZone = zoneDateTime.Hour;
int minuteZone = zoneDateTime.Minute;
if (hourZone == hourComparison && minuteZone == minuteComparison)
{
zoneIdsCheck.Add(zone.ToString());
Console.WriteLine($"{zone} / {zoneDateTime}");
}
}
return zoneIdsCheck;
}
}
}
If someone has a better solution please let me know.
Related
I'm working with the Office365 Outlook Calendar API. I need to get events of a specific time range. I tried to compare the DateTimeTimeZone values inside of the foreach command, but it seems like it only supports a == operator:
if ( calendarEvent.Start >= new DateTimeTimeZone()
{
TimeZone = TimeZoneInfo.Local.Id,
DateTime = DateTime.Now.ToString("s")
})
This code snippet fails with the error: Cannot apply operator '>=' to operands of type 'Microsoft.Office365.OutlookServices.DateTimeTimeZone' and 'Microsoft.Office365.OutlookServices.DateTimeTimeZone'
Are there any other ways get events of a specific time range, e.g. future events?
This is my GetEvents()-method so far:
[Route("GetEvents")]
public async Task GetEvents()
{
//Get client
OutlookServicesClient client = await this.GetClient();
//Get events
var events = await client.Me.Events
.Take(10)
.ExecuteAsync();
foreach (var calendarEvent in events.CurrentPage)
{
//
if ( calendarEvent.Subject == "Test 1" )
{
System.Diagnostics.Debug.WriteLine("Event '{0}'.", calendarEvent.Subject) ;
}
}
}
You should use the CalendarView to get events within a time range.
DateTimeOffset startDateTime, endDateTime;
var events = client.Me.GetCalendarView(startDateTime, endDateTime);
I have added custom attribute lastLogonTime syntax: UTC Coded Time. I extended UserPrincipal class to GET/SET that custom attribute.
...
[DirectoryProperty("lastLogonTime")]
public DateTime? LastLogonTime
{
get
{
object[] result = this.ExtensionGet("lastLogonTime");
if (result != null && result.Count() > 0) return (DateTime?)result[0];
return null;
}
set
{
this.ExtensionSet("lastLogonTime", value);
}
}
...
I have also extended AdvancedFilters to be able to search by this custom attribute.
MyUserPrincipalSearch searchFilter;
new public MyUserPrincipalSearch AdvancedSearchFilter
{
get
{
if (null == searchFilter)
searchFilter = new MyUserPrincipalSearch(this);
return searchFilter;
}
}
public class MyUserPrincipalSearch: AdvancedFilters
{
public MyUserPrincipalSearch(Principal p) : base(p) { }
public void LastLogonTime (DateTime? lastLogonTime, MatchType mt)
{
this.AdvancedFilterSet("lastLogonTime", lastLogonTime.Value, typeof(DateTime?), mt);
}
}
Now, I would like to search through all users who has lastLogonTime less than a day.
using (PrincipalContext ctx = ADLDSUtility.Users)
{
MyUserPrincipal filter = new MyUserPrincipal(ctx);
filter.AdvancedSearchFilter.LastLogonTime((DateTime.Now - new TimeSpan(1,0,0,0,0)), MatchType.LessThan);
PrincipalSearcher ps = new PrincipalSearcher(filter);
foreach (MyUserPrincipal p in ps.FindAll())
{
//my custom code
}
}
The above search is not returning me any results. I have test users who have not logged in in the last couple days.
I have tried MatchType.GreaterThan, MatchType.Equals. None of them are returning any results, yet there're users who match those criteria.
The only filter that does work is
filter.AdvancedSearchFilter.LastLogonTime(DateTime.Now , MatchType.NotEquals);
But this is basically returning all users. Any ideas why my search result is not returning any results?
My goal is to search for all users who's last logon time is less than X days.
I'm open to other solutions as long as I get those users.
P.S. I do know a way around this. Loop through all users, get their lastLogonTime and then do a comparison, but that's just an overkill for what I'm doing.
After spending sometimes on this issue, I found the problem.
As I mentioned on my post the custom attribute lastLogonTime has syntax: UTC Coded Time. However, the date and time is not getting stored as DateTime. It's actually getting stored as string in this format:
yyyyMMddHHmmss.0Z
How I ended up solving this issue is by modifying my AdvancedSearchFilter.LastLogonTime to search using formatted string.
public void LastLogonTime (DateTime? lastLogonTime, MatchType mt)
{
const string lastLogonTimeFormat = "yyyyMMddHHmmss.0Z";
this.AdvancedFilterSet("lastLogonTime", lastLogonTime.Value.ToUniversalTime().ToString(lastLogonTimeFormat), typeof(string), mt);
}
Hope this helps someone.
I have some stock data that I'm trying to sort using linq, however I'm very unfamiliar with linq and cannot understand the documentation.
Right now I have a list of bars (a class I've created that holds the stock data) and it's all of the stock data for each day since 1990. Now I'm trying to group this stock data by year and month so I can turn daily stock data into monthly stock data (the resolution of the stock).
public class Stock
{
private string stockSymboll;
private string period;
private List<bar> aBar = new List<bar>();
private DateTime startingDate;
private DateTime endingDate;
enum period { DAILY, WEEKLY, MONTHLY };
private period PeriodType;
}
public class bar
{
private double open;
private double high;
private double low;
private double close;
private double volume;
private DateTime stockDate;
}
within the stock class I have a function that I'm trying to use to convert from a list of daily data to a list of monthly data, in order from most recent to least recent.
Here is what I've attempted:
stock convertPeriod(Period pt)
{
stock newStock = new Stock(stockName, startingDate, endingDate, period);
if (pt == Periode.MONTHLY)
{
List<bar> monthlyGroup = new List<bar>();
var group1 = (from b in bar group c by b.getDate().Month);
var group2 = from g in group1 group g by g.getDate().Year)
return...;
}
}
However I've discovered that you cannot sort a var. So I was thinking the best way would be to attempt a nested query in linq, however I can hardly seem to even get basic queries to work. Any help would be greatly appreciated.
I'm not 100% clear on what contract you're supposed to be setting up, but as I understand it, you want to:
Receive an IEnumerable<Bar>, and
Return an IEnumerable<Bar> such that StockDate is the first day of the year and month for the summarized stocks, all sorted descending by date.
As I understand it, Stock is more or less irrelevant to your true question here. If I'm incorrect in that, let me know and I can help you take this that one step further.
You have a good start on this in your LINQ. I'm a little confused about your use of private fields in the types, but I'm assuming those to be typos, and that your actual code uses public, probably properties.
I'll do this as a couple separate methods just to make what I'm doing more clear, but you may want to bring them together in the interest of performance. Particularly since I order the collection twice, effectively.
This method groups and sorts the data, based on the first day of their year-month set. Note that you can actually perform a grouping on an anonymous type. Sorting doesn't work on the anonymous object itself, as you noted, but it does work on its properties.
public IEnumerable<IEnumerable<Bar>> GroupIntoMonths(IEnumerable<Bar> bars)
{
return bars.GroupBy(c => new { c.StockDate.Year, c.StockDate.Month })
.OrderByDescending(c => c.Key.Year)
.ThenByDescending(c => c.Key.Month);
}
The choice is yours whether you prefer to group on an instantiated DateTime object with a date set of one, or what I've done here. I don't touch the Key property again, so I was fine effectively losing track of it after I left the method. Other implementations might drive you to make a different decision on that.
Once you've got that, it's a matter of converting an IEnumerable<Bar> into a single Bar that summarizes the whole period.
public IEnumerable<Bar> GroupIntoBars(IEnumerable<IGrouping<DateTime, Bar>> groups)
{
return groups.Select(GetBar);
}
public Bar GetBar(IEnumerable<Bar> bars)
{
Bar ret = new Bar();
Bar last = null;
int index = -1;
foreach(var v in bars.OrderBy(c => c.StartingDate))
{
index++;
if(index == 0)
{
ret.Open = v.Open;
ret.StockDate = v.StockDate;
ret.High = v.High;
ret.Low = v.Low;
}
else
{
ret.High = Math.Max(ret.High, v.High);
ret.Low= Math.Max(ret.Low, v.Low);
}
last = v;
}
if(last == null) throw new ArgumentException("Collection cannot be empty!");
ret.Close = last.Close;
return ret;
}
I think that method is pretty straight-forward, but let me know if I can clear anything up.
You can group by multiple properties at once by specifying them in an anonymous object that will be the group key:
var monthlyGroup = aBar.OrderBy(bar => bar.stockDate)
.GroupBy(bar => new { Year = bar.stockDate.Year, Month = bar.stockDate.Month })
//create bars from groups
.Select(g => new bar()
{
open = g.First().open,
high = g.Max(b => b.high),
low = g.Min(b => b.low),
close = g.Last().close,
volume = g.Average(b => b.volume),
stockDate = new DateTime(g.Key.Year, g.Key.Month, 1)
})
.ToList();
Sorry but I prefer the functions syntax of linq.
I noticed that fields in bar class are private so they will be inaccessible. However, I assume that you have properties for each field.
In that case you will have to replace field names with property names in the code above.
I have a class storedetails which get different values from database. fetching these values from database and calculating takes a long time(due to poor design of the database over 76 different queries for one store).
My implementation for generating the report is as below.
string week = "32";
string year = "2013";
string[] storecode = getallstoreforweekandyear(week, year); // get all store code that were active for the week and year
ArrayList ar = new ArrayList();
foreach (string item in storecode)
{
storedetails sd = new storedetails(item, year, week);// this initializion I want to move to another thread because it is taking time.
ar.Add(sd);
}
ar.TrimToSize();
DataTable dt = getdtfromarraylist(ar);// convert the arraylist of class to datatable
Gridview1.Datasourc=dt;
My implementation of class is in over 2000 line of code
class storedetails
{
public storedetails(string store,string year, string week)
{
//time taking implementation
}
}
Is it possible that initialization of classes occur in separate threads, so I can gain some speed?
Have you checked out the Task Parallel Libraries in .NET 4.0 - they simplify threading a lot.
http://msdn.microsoft.com/en-us/library/dd460717(v=vs.110).aspx
object locker = new object();
Parallel.ForEach (storecode => item
{
storedetails sd = new storedetails(item, year, week);
lock(locker)
{
ar.Add(sd);
}
});
I try to cache my userlist, so that when 200 users are online, there are not 200 database querys every 10 seconds.
I have this code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Business
{
public class UserList
{
private static object locker = new object();
public static List<DAL.OnlineList> userList;
public static DateTime date;
}
}
-
public static string GetOnlineList(HttpContext con)
{
List<DAL.OnlineList> onlineList = new List<DAL.OnlineList>();
if (Business.UserList.date == DateTime.MinValue || Business.UserList.date < DateTime.Now.AddSeconds(-30))
{
Business.UserList.date = DateTime.Now;
onlineList = DAL.UserDAL.GetAllOnlineUser().OrderBy(x => x.Username).ToList();
Business.UserList.userList = onlineList;
}
else
{
onlineList = Business.UserList.userList;
}
//Before
//List<DAL.OnlineList> onlineList = DAL.UserDAL.GetAllOnlineUser().OrderBy(x => x.Username).ToList();
}
The method GetOnlineList is called every 10 seconds from a WebMethod / pageMethod / JavaScript-call.
So before it was: 200 Users, every 10 seconds = 200 x 10 x 6 = 12000 db-querys per minute.
Then my code is right, the first user will load the list from the database and store it - and it will be refreshed every 30 seconds - correct?
I think that the condition in your code snippet needs an adjustment
if (Business.UserList.date == DateTime.MinValue ||
Business.UserList.date > DateTime.Now.AddSeconds(-30))
You can always use the built in caching mechanism ASP.NET that has. You can read about it here.
Basically, you have two options to cache objects with sliding expiration and absolute expiration.
With sliding expiration an object remains in the cache if you retrieve it sooner than the expiration timespan you have set. For example, if you set a timespan of 2 minutes and you retrieve the object every 1 minute it will remain forever in the cache.
With absolute expiration, an object stays in the cache based on the timespan regardless of how many times it has been retrieved.
In your example, you are have the absolute expiration logic. Here is an example on how to use it:
public List<DAL.OnlineList> Users
{
get
{
List<DAL.OnlineList> users = null;
string CacheKey = "dal_users";
users = HttpContext.Current.Cache[CacheKey];
if ((users == null))
{
users = DAL.UserDAL.GetAllOnlineUser()
.OrderBy(x => x.Username).ToList();
HttpContext.Current.Cache.Add(CacheKey, users, Nothing,
DateTime.Now.AddSeconds(30), Caching.Cache.NoSlidingExpiration,
CacheItemPriority.Default, null);
}
return users;
}
}