2020年5月28日 星期四

[筆記] 以C# 取得 此年份的所有週、週數、每週起始日、結束日

最近在經手的某個專案當中,遇見了需要取得年度週別日期的需求。
經過一番查詢以及苦戰後,
用C# 土法煉鋼的手法編出了符合ISO 8601的解決方法, 
但在事後檢視的時候,經過同事建議我才發現在SQL當中,有著更輕鬆解決這個問題的方法呢。

以C#方式取得週數、週別、起始日期、結束日期


#region Week of the Year
       #region Week of the Year
        //依據今天日期 往前第 iSkip   周 ,取 iTake 周
        public static List GetCurrentDateRangeList(int iSkip = 5, int iTake = 5)
        {
            string nowWeekofYear = GetCurrentWeekAndYear(DateTime.Now);

            var allWeekList = GetWholeYearWeek();

            var index = allWeekList.IndexOf(allWeekList.Where(x => x.weekYear == nowWeekofYear).FirstOrDefault()) + 1;

            var currentList = allWeekList.Skip(index - iSkip).Take(iTake);

            return currentList.ToList();

        }

        public static string GetCurrentWeekAndYear(DateTime time)
        {

            DayOfWeek day = CultureInfo.InvariantCulture.Calendar.GetDayOfWeek(time);
            if (day >= DayOfWeek.Monday && day <= DayOfWeek.Wednesday)
            {
                time = time.AddDays(3);
            }
            return time.Year + "-" + CultureInfo.InvariantCulture.Calendar.GetWeekOfYear(time, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
        }

        //取得現去年+今年度的所有周別
        public static List GetWholeYearWeek()
        {
            List li = new List();
            li.AddRange(GetWeekList(DateTime.Now.Year - 1));
            li.AddRange(GetWeekList(DateTime.Now.Year));
            return li;
        }


        public static List GetWeekList(int iYear)
        {

            var jan1 = new DateTime(iYear, 1, 1);
            //ISO 8601規範 禮拜一是每周的第 一天
            var startOfFirstWeek = jan1.AddDays(1 - (int)(jan1.DayOfWeek));

            var fullWeeks = Enumerable.Range(0, 54).Select(i => new { weekStart = startOfFirstWeek.AddDays(i * 7) }).TakeWhile(x => x.weekStart.Year <= jan1.Year).Select(x => new { x.weekStart, weekFinish = x.weekStart.AddDays(6) }).ToList();
            //ISO 8601規範 每年最後一周,有多於四日在當年的為 新年度的第一周 或舊年度的最後一周 2019/12/31 (二) 該周則為2020的第一周 非2019的最後一周
            if (fullWeeks.Last().weekStart.Year != fullWeeks.Last().weekFinish.Year)
            {
                var lastDTofYear = DateTime.Parse(fullWeeks.Last().weekStart.Year.ToString() + "/12/31");
                DayOfWeek day = CultureInfo.InvariantCulture.Calendar.GetDayOfWeek(lastDTofYear);

                if (day >= DayOfWeek.Monday && day <= DayOfWeek.Wednesday)
                {
                    // 該年12/31 在禮拜1~3 說明一月份在該周有四天以上 ,刪除最後一周
                    fullWeeks.Remove(fullWeeks.Last());
                }

                var fstweeklastDTofYear = DateTime.Parse(fullWeeks.First().weekStart.Year.ToString() + "/12/31");
                day = CultureInfo.InvariantCulture.Calendar.GetDayOfWeek(fstweeklastDTofYear);
                if (day >= DayOfWeek.Thursday && day <= DayOfWeek.Sunday)
                {
                    // 該年第一周的12/31 在禮拜4~日 說明一月份在該周有四天以上 ,刪除第一周
                    fullWeeks.Remove(fullWeeks.First());
                }
            }


            var weeks = fullWeeks.SkipWhile(x => x.weekFinish < jan1.AddDays(1))
                    .Select((x, i) => new YearWeek
                    {
                        weekStart = x.weekStart,
                        weekFinish = x.weekFinish,
                        weekNum = i + 1,
                        weekYear = x.weekFinish.Year + "-" + (i + 1),
                    }).ToList();

            return weeks;
        }


        #endregion /Week of the Year
        
    public class YearWeek
    {
        public DateTime weekStart { get; set; }
        public DateTime weekFinish { get; set; }
        public string weekYear { get; set; }
        public int weekNum { get; set; }
    }
執行的結果如圖:


以SQL方式取得週數、週別、起始日期、結束日期


    /************SQL************/
    Declare @table(Date DATE, [Year] Nvarchar(10), [WeekNum] INT )
    DECLARE @i INT = 1, @SDate DATE = N'2020/1/1'
    WHILE @i<=366
    BEGIN
     INSERT INTO @table  VALUES(@SDate, CONVERT(NVARCHAR, DATEPART(YEAR, @SDate)), CONVERT(NVARCHAR, DATEPART(WEEK, @SDate)))
     SET @SDate = DATEADD(DAY, 1, @SDate)
     SET @i = @i + 1
    END

執行的結果如圖 : 


2020年4月14日 星期二

[TSQL] 產生 以每30分鐘為單位的 時間清單


DECLARE @dtStart AS DATETIME ='20200417 10:00:00'
        ,@dtEnd AS DATETIME = '20200417 23:59:00'
        ,@iInterval AS INT = 30;  --30 min interval


WITH aCTE
AS(
    SELECT 
        @dtStart AS StartDateTime,
        DATEADD(MINUTE,@iInterval,@dtStart) AS EndDateTime
    UNION ALL
    SELECT 
        DATEADD(MINUTE,@iInterval,StartDateTime),
        DATEADD(MINUTE,@iInterval,EndDateTime)
    FROM aCTE
    WHERE
        DATEADD(MINUTE,@iInterval,EndDateTime) <= @dtEnd
)

SELECT 
    -- 10:00:00 AM 
    CONVERT(VARCHAR(10),StartDateTime,114) ,
  RIGHT(CONVERT(VARCHAR(30), StartDateTime, 9), 2)  ,
    -- 10:30:00 AM
    CONVERT(VARCHAR(10),EndDateTime,114) ,
   RIGHT(CONVERT(VARCHAR(30), EndDateTime, 9), 2) AS Result
FROM aCTE

2019年10月2日 星期三

[Graphic DB] 圖形資料庫學習筆記 (一)..... 希望會有二



最近在看一些新的技術,預防未來可能為之而來的挑戰,
不然就來研究看看甚麼叫做圖形資料庫吧!!

我們先來看看各家大廠對於圖形資料庫的定義 ,

Amazon :

圖形資料庫專門用於存放和導覽關係。「關係」是圖形資料庫中的第一類物件,圖形資料庫最主要的價值也是源自於這些關係。圖形資料庫使用節點來存放資料實體,並利用邊緣來存放各實體間的關係。邊緣一定包含起始節點、結束節點、類型和方向。邊緣可以用來描述父項與子項的關係、動作、所有權等等。一個節點所能擁有的關係數量與關係類型沒有限制。


Microsoft :


圖表資料庫是節點 (或頂點) 與邊線 (或關聯性) 的集合。 節點表示實體 (例如個人或組織),邊線代表其所連結之兩個節點的關聯性 (例如按讚數或朋友數)。節點和邊緣都可能有與其相關聯的屬性。以下是一些功能,使圖表資料庫的唯一:
1. 邊緣或關聯性是第一級實體中的圖表資料庫,可以有屬性與其相關聯。
2. 單一邊緣可以彈性地連接圖形資料庫中的多個節點。
3. 您可以表示模式比對和多重躍點瀏覽查詢輕鬆。
4. 輕鬆地可以表示遞移封閉和多型查詢。



依照我的理解
1.圖形資料庫屬於NoSql的一種資料庫設計架構
2.是由「節點」、「關聯」 作為主軸而形成的一種資料庫。
3.節點可視為每一個個體,像是台灣是一個個體,新北市、台北市各為一個個體
4.每一個節點 與 節點之間的關係,就稱之為關聯
 例如: 
 「台北市」是"歸屬於"「台灣」的一個城市、
 「中山區」是"劃分於" 「台北市」的一個區、
  這其中的 "歸屬於" 以及 "劃分於" 就是關聯。






例圖 : 圖形資料庫範例








教學影片、文件
1. 孫在楊老師的Neo4J教學
2.  Eric Lee @開源⼈人年年會 中發表的教學文件

文獻參考:
1.微軟SQL GRAPH
2.AMAZON

2019年4月17日 星期三

Visual Studio 2017 Web專案偵錯時自動開啟新視窗

要防止每次開啟Web專案偵錯時,都會重新開啟新視窗有幾個部分需要修改

 1.
工具>選項>一般>Web專案
取消勾選 > [在瀏覽器視窗關閉時停止偵錯工具,在偵錯停止時關閉瀏覽器]


2.
工具>選項>一般>偵錯

取消勾選 > [為ASP.NET 啟用JavaScript偵錯(Chrome、Edge 及IE)]



3.


2018年11月9日 星期五

[MVC] WebAPI and Azure Blob Storage Upload - 簡易的將檔案上傳到Azure Blob Storage

因為工作有用到,所以在這裡留下有關於檔案上傳到Azure Blob Storage 的紀錄


1. Azure Storage
先到Azure Storage中 設定完Blob 儲存體後,取得連線字串



然後建立好Blob Container



將連線字串加入WebConfig中

    <add key="FileUploadAzureBlob" value="DefaultEndpointsProtocol=https;AccountName={blob_storage_name};AccountKey**********************;EndpointSuffix=core.windows.net" />


2. 在前端Html 中先建立 類別為file 的 Input  以及 Upload 的按鈕



<input class="col-md-12" id="inputFile" multiple="" name="files[]" type="file" />
<button class="btn btn-success" id="btnUpload" type="button"> Upload </button>

如下所示 :

3. 在JavaScript的區塊中建立 Upload 按鈕的Event




 $(document).on('click', '#btnUpload', function () {
        var files = $('#inputFile')[0].files;

        //FormData 是Html表單中的 <form > 
        //此處我們利用建立表單的方式儲存檔案
        //之後再透過Ajax的方式,將檔案傳遞到 WebApi 或Controller 
        var fileData = new FormData();
        $.each(files, function (i, o) {
            fileData.append(o.name, o);  //將檔案"們" Append 進表單
        });
        

        if (Object.keys(files).length < 1) {
            return;       //若input 中沒有檔案,就不使用Ajax
        } 

    
        $.ajax({
            url: '/AzureApi/Upload/',
            type: "POST",
            contentType: false, // 不設定任何的 Content Header
            processData: false, // 不進行資料轉換的步驟
            data: fileData,     //將檔案放進body中
            success: function (result) {
                alert('檔案上傳成功');
            }
        });
    });

4. WebApi的建立
這裡會使用到 WindowsAzure.Storage 的Nuget 套件
著手紀錄的時候最新版本為 9.3.2,未來有更新的版本還是建議使用新的版本
請參照 : NuGet Gallery







using Microsoft.WindowsAzure.Storage;            //引用
using Microsoft.WindowsAzure.Storage.Blob;       //引用

namespace TASSWeb.Controllers.Api
{

    public class AzureApiController : BaseApiController
    {

        [HttpPost]
        [Route("AzureApi/Upload/")]       
        public async Task PostUpload()
        {
            //FormData Setting 
            var provider = new MultipartMemoryStreamProvider();
            await Request.Content.ReadAsMultipartAsync(provider);   //將檔案放進provider內

            //Connection String , and Azure Blob Container 
            string sConnStr = System.Configuration.ConfigurationManager.AppSettings["FileUploadAzureBlob"].ToString();
            string sContainer = "filupload"; //需要為小寫英文字母

            //建立與Storage的連線以及認證
            CloudStorageAccount storageAccount = CloudStorageAccount.Parse(sConnStr);

            //連接到Blob Client
            CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();

           //使用GetBlockBlobReference去取得 CloudBlockBlob 物件的參考
            CloudBlockBlob blockBlob = container.GetBlockBlobReference(guFileID.ToString());

           //將provider內的資料轉為Stream
           Stream filestream = await provider.Files[0].ReadAsStreamAsync();

            //檢查容器是否存在,不存在則建立
            container.CreateIfNotExists();
            try
            {
                //使用UploadFromStream 將Stream的檔案上傳至Azure Blob Storage 中的Container
                //UploadFromStream  或是 UploadFromStreamAsync 這兩種方法 都會已覆蓋的方式上傳檔案
                blockBlob.UploadFromStream(filestream);
            }
            catch (Exception ex){
                return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex.Message);
            }
            return Request.CreateResponse(HttpStatusCode.OK);
        }
    }
}

2018年7月29日 星期日

[Azure WebApp] TimeZone

因網站發布至Azure Web Application 之後,發現凡是使用到


DateTime.Now();

通通一率是UTC時間。

經同事查證,只單純修改WebConfig 的時間是無效的,
需要在 Azure WebApp 中 設定 [ 應用程式設定 ]

實際操作如下 :


圖1.Web Application 中點選應用程式設定



圖2. 輸入應用程式設定 WEBSITE_TIME_ZONE    :    自己的時區  (eg. Taipei Standard Time )。






參考:



2018年6月18日 星期一

C# Connection String & DataAdapter Fill

  以前的紀錄不見了,只好重新紀錄一次常用的Connection String .

在Web.config 中 新增 Connectionstring
----------------------------------------------------------------------------------------------------------------------

  <connectionStrings> 
    <add name="ConnectionString1" connectionString="Data Source=DatabaseName;Initial Catalog=AdventureWorksLT2008;Persist Security Info=True;User ID=xx;Password=xxxxxxxxx" providerName="System.Data.SqlClient"/> 
  </connectionStrings> 
 
----------------------------------------------------------------------------------------------------------------------
 在aspx中新增telerik GridView
---------------------------------------------------

   <div>

        <telerik:RadGrid ID="RadGrid1" runat="server" AllowPaging="True" Skin="MetroTouch"></telerik:RadGrid>

        <asp:Label ID="Label1" runat="server" Text="Label"/>

    </div>

----------------------------------------------------------------------------------------------------------------------
aspx.cs中 新增 DataBind 的Function ,並在頁面啟動時就呼叫
---------------------------------------------------

protected void Page_Load(object sender, EventArgs e)

    {

        //呼叫Function

        DataBind_GridView();

    }

----------------------------------------------------------------------------------------------------------------------
Function 
---------------------------------------------------

    // Function Start

    private void DataBind_GridView() {

       //Connection String

        string Connection1 = ConfigurationManager.ConnectionStrings["ConnectionString1"].ConnectionString;

        string selectDB = "SELECT * FROM SalesLT.Customer";     

    

        SqlConnection db = new SqlConnection(Connection1); //new Sql 連線

        SqlCommand cmd = new SqlCommand(selectDB, db); //Sql Command

        SqlDataAdapter da = new SqlDataAdapter(cmd);

        DataSet ds = new DataSet();

        da.Fill(ds);

        RadGrid1.DataSource = ds;

    }





----------------------------------------------------------------------------------------------------------------------