Thursday, October 21, 2010

Week range knowing week number

In one of my applications I needed to display the range of a week knowing only the week number from a specific year. After I realize that a functionality like this is not provided out of the box I had to do some research.

I started with a DateTime extension that I founded at http://stackoverflow.com/questions/38039/how-can-i-get-the-datetime-for-the-start-of-the-week

public static class DateTimeExtensions

{


    public static DateTime StartOfWeek(this DateTime dt, DayOfWeek startOfWeek)



    {



        int diff = dt.DayOfWeek - startOfWeek;



        if (diff < 0)



        {



            diff += 7;



        }



 



        return dt.AddDays(-1 * diff).Date;



    }



} 




Ok. This will help me to find the first day of a week for a given date. Next only to test I created a console application where given a date I found the week number and after that I print the week range.



At the beginning we have to establish the first day of the week. The reason is that in different cultures the week can start on Monday, Sunday or who knows what day.



public static DayOfWeek firstDayOfWeek = DayOfWeek.Monday;


The rest of the code is simple. I added the data as string to simulate the reading from a config file. Here it is:





using System;



using System.Collections.Generic;



using System.Linq;



using System.Text;



using System.Globalization;



 



namespace WeekRange



{



    public static class DateTimeExtensions



    {



        public static DateTime StartOfWeek(this DateTime dt, DayOfWeek startOfWeek)



        {



            int diff = dt.DayOfWeek - startOfWeek;



            if (diff < 0)



            {



                diff += 7;



            }



 



            return dt.AddDays(-1 * diff).Date;



        }



    } 



 



    class Program



    {



        public static DayOfWeek firstDayOfWeek = DayOfWeek.Monday;



 



        public static int GetNumberOfWeekByDate(DateTime theTime)



        {



            CultureInfo ciGetNumber = CultureInfo.CurrentCulture;



            int returnNumber = ciGetNumber.Calendar.GetWeekOfYear(theTime, CalendarWeekRule.FirstDay, firstDayOfWeek);



            return returnNumber;



        }



 



        public static int GetNumberOfWeeksInYear(int theYear)



        {



            DateTime lastMoment = new DateTime(theYear, 12, 31);



            return GetNumberOfWeekByDate(lastMoment);



        }



 



        public static void ShowShortPeriod(DateTime theDate, int yearWeeksNumber)



        {



            int fromNext = 0;



 



            int weekNumber = GetNumberOfWeekByDate(theDate);



            if (yearWeeksNumber == weekNumber)



            {



                DateTime firstDayOfNextYear = new DateTime(theDate.Year + 1, 1, 1);



                if (firstDayOfNextYear.ToShortDateString() != firstDayOfNextYear.StartOfWeek(firstDayOfWeek).ToShortDateString())



                {



                    weekNumber = 1;



                    fromNext = theDate.Year + 1;



                }



                else



                {



                    fromNext = theDate.Year;



                }



            }



            else



            {



                fromNext = theDate.Year;



            }



 



            DateTime fdt = theDate.StartOfWeek(firstDayOfWeek);



            DateTime ldt = fdt.AddDays(6);



 



            Console.Write("{2} is in week {0} from year {1}", weekNumber, fromNext, theDate.ToString("dd-MMM-yyyy"));            



        }        



 



        public static string GetWeekRange(int yearNr, int weekNr, int yearWeeksNumber)



        {



            DateTime firstDayOfYear = new DateTime(yearNr, 1, 1);



            DateTime firstWeekStart = firstDayOfYear.StartOfWeek(firstDayOfWeek);



 



            DateTime desiredWeekStartDate = firstWeekStart.AddDays(weekNr * 7 - 7);



            DateTime desiredWeekEndDate = desiredWeekStartDate.AddDays(6);



            return desiredWeekStartDate.ToString("dd-MMM-yyyy") + " to " + desiredWeekEndDate.ToString("dd-MMM-yyyy");



        }



 



        static void Main(string[] args)



        {



            string strCurrentDate = "2010/10/21";



            string[] strCurrentDateArray = strCurrentDate.Split('/');



 



            DateTime dt = new DateTime(Convert.ToInt32(strCurrentDateArray[0]), 



                            Convert.ToInt32(strCurrentDateArray[1]), 



                            Convert.ToInt32(strCurrentDateArray[2]));            



 



            // print week number for a specified date



            ShowShortPeriod(dt, GetNumberOfWeeksInYear(dt.Year));



 



            Console.WriteLine("");



 



            //display the week range



            int theYear = Convert.ToInt32(strCurrentDateArray[0]);



            int theYearWeeksNumber = GetNumberOfWeeksInYear(theYear);            



            int weekNumber = GetNumberOfWeekByDate(dt);



            Console.WriteLine("week range from {0}", GetWeekRange(theYear, weekNumber, theYearWeeksNumber));



 



            Console.ReadKey();



        }



    }



}




The output of this is:



result



 



Hope this helps.

CRUD sample for list items using WCF data services and SPLINQ

The purpose of this post is to show how can we do CRUD operations on SharePoint 2010 lists using WCF data services. Actually SharePoint 2010 exposes list data trough REST (Representational State Transfer) service that you can consume in your projects. I will show now how can we use this in code. For this we will use also LINQ to SharePoint called SPLINQ. One advantage of this over CAML that is strong typed and an error can be discovered at compilation time for example.

We have to be aware that the REST based access is not supported for external lists.

For this example I created a custom list of towns that we will use. To this list I add some columns like Country, Population and Website. I also add some data.

listcolumns

listdefaultdata

Now, knowing that the data services are located in the “_vti_bin” directory and is called “ListData.svc” we can start programming. First we can create a simple console application and add a service reference. Give a name to the namespace. I called this CFGService.

service_reference

Next step is to add all required references to Microsoft.SharePoint.Linq and System.Net.
Now we can start writing the code and we will use the DataContext class that was generated when we added the service reference.

First, creating a new entry in the list. Because the DataContext class is strongly typed it knows about our list. We also need to add the credentials. In my example I added the DefaultCredentials.

We will create a new TownsItem object and this to the context by using AddToTowns method. At the end we have to save all the changes by calling SaveChanges. I also added the url as global variable.

public static string servUrl = "http://myserver:111/sites/Test2/_vti_bin/ListData.svc";





public static void CreateData()



 {



     CFGService.Test2DataContext ctx = new CFGService.Test2DataContext(new Uri(servUrl));



     ctx.Credentials = CredentialCache.DefaultCredentials;



 



     CFGService.TownsItem town = new CFGService.TownsItem();



     town.Name = "London";



     town.Country = "United Kingdom";



     town.Population = 7600000;



     town.Website = "http://www.london.gov.uk";



 



     ctx.AddToTowns(town);



     ctx.SaveChanges();



 }





To read the data existing in the list we have the function ReadAllData. Here we have an IEnumerable of TownsItem. Now we iterate through the collection and display the values.





public static void ReadAllData()



 {



     CFGService.Test2DataContext ctx = new CFGService.Test2DataContext(new Uri(servUrl));



     ctx.Credentials = CredentialCache.DefaultCredentials;



 



     IEnumerable<CFGService.TownsItem> towns = from t in ctx.Towns



                                               orderby t.Name



                                               select t;



     foreach (CFGService.TownsItem item in towns)



     {



         Console.WriteLine(String.Format("{0} - {1} - {2} - {3}", item.Name, item.Country, item.Population, item.Website));



     }



 



     Console.ReadKey();



 }




As alternative we can have this code to display only the name for example:





var cities = from c in ctx.Towns



              select c;



 



 foreach (var city in cities)



 {



     Console.WriteLine(city.Name);                



 }




Next, to update the Item we call the UpdateData method. We get the item with the required name and update the population number. Need to call the UpdateObject at the end in order to register the change on the server.





public static void UpdateData()



{



    CFGService.Test2DataContext ctx = new CFGService.Test2DataContext(new Uri(servUrl));



    ctx.Credentials = CredentialCache.DefaultCredentials;



 



    CFGService.TownsItem item = (from t in ctx.Towns



                                 where t.Name == "London"



                                 select t).Single();



    item.Population = 7700000;



    ctx.UpdateObject(item);



    ctx.SaveChanges();



}




To delete we call the DeleteData method.





public static void DeleteData()



{



    CFGService.Test2DataContext ctx = new CFGService.Test2DataContext(new Uri(servUrl));



    ctx.Credentials = CredentialCache.DefaultCredentials;



 



    CFGService.TownsItem item = (from t in ctx.Towns



                                 where t.Name == "London"



                                 select t).Single();



 



    ctx.DeleteObject(item);



    ctx.SaveChanges();



}




And this is it , a simple example to implement the CRUD operations.