BLOG main image
분류 전체보기 (68)
excel.101 (0)
rewind (9)
(3)
(2)
목공 (3)
(3)
me2day (0)
The Ethereal Void (9)
코드 (14)
귀찮은것 (0)
Visitors up to today!
Today hit, Yesterday hit
daisy rss
tistory 티스토리 가입하기!
'.NET'에 해당되는 글 4건
2012. 7. 4. 18:35

이런 저런 작업을 하다보면, 두 일자를 포함하는 날짜 혹은 기간 범위는 꽤 많이 쓰이는 것 중에 하나인데, 이게 이상하게도 닷넷 코어 부분에 포함이 되어 있지 않다. 외국 사이트에 가끔 찾아보면 Period 같은 클래스를 작성해서 사용하기도 하던데, 끌어다 쓰긴 좀 그렇고, 자주 사용되는 것 중에 하나라 아예 필요한 부분 부분 따로 라이브러리로 작성해두었다.


이름은 DateRange (...)


구구절절 쓰면 골치 아프니, 바로 코드로 ... 

다음과 같이 사용이 가능하다.


// 2012년 1월 1일 0시부터 2012년 12월 31일 0시까지
DateRange year2012 = new DateRange(2012);
Console.WriteLine(String.Format("{0} ~ {1}"), year2012.Start, year2012.End));
// 또는
Console.WriteLine(year2012);
// output: 2012-01-01 ~ 2012-12-31

// 2012년 3월 전체
DateRange month201203 = new DateRange(2012, 3);
// 기간이 만월인지? 
Assert.IsTrue(month201203.IsFullMonth); // true !

// 2010년 부터 2012년까지
DateRange year2010to2012 = new DateRange(new DateTime(2010, 1, 1), new DateTime(2012, 12, 31));

// 오늘 날짜를 기준으로 이번 주 범위를 반환한다. 주 시작은 일요일에서 토요일까지 -
// 이 부분은 문화권 마다 다르게 처리해줘야 되는데, 아직 그 부분은 미구현.
// 근데 이렇게 시간에 따라 변하는 값을 정적 속성으로 처리하는게 왠지 꺼름직해서 (디자인 상으로 그다지 좋지 않다.) 지울 예정 -_-
DateRange thisWeek = DateRange.ThisWeek;

// 특정일자, 년도를 기준으로 분기, 반기 범위
// 2012년도의 1분기
DateRange firstQuaterOf2012 = DateRange.GetQuater(2012, 1);

// 2012년도의 후기
// 지정된 날짜를 기준으로 해당 년도의 반기를 반환
DateRange lastHalfYearOf2012 = DateRange.GetHalfYearly(new DateTime(2012, 7, 1));

// 범위 조작
DateRange period1 = new DateRange(new DateTime(2010, 1, 1), new DateTime(2010, 1, 11));
// 기간 끝날짜를 월말로 확장한다.
period1.ToMonthEnd();
Console.WriteLine(period1.End);
// output: 2010-01-31

// 1월에 3개월을 더하면? 4월이다. 4월달의 범위를 반환.
DateRange period2 = period1.AddMonths(3); // start: 2010-04-01, end: 2010-04-30 (말일이 31일이 아니라 30일이다. 중요)

// 2010년에 1년을 더하면 2011년 범위를 반환.
DateRange period3 = period2.AddYears(1);  // start: 2011-04-01, end: 2011-04-30

// 기간 그대로 앞 뒤로 이동이 가능하다. 이때 각 시작, 끝 날짜에 TimeSpan 기간에 대한 Add, Substract 연산이 처리된다.
period3.ShiftForward(TimeSpan.FromDays(10)); // 10일 이전 범위
period3.ShiftBackward(TimeSpan.FromDays(5)); // 5일 이후 범위

// 특정일자가 기간에 포함되는지 여부 확인
Assert.IsTrue(period1.Contains(new DateTime(2010, 1, 5))); // true !

// 기간의 각각 일자에 대한 반복처리
period1.ForEach(new Action(delegate(DateTime date)
{
// 1월 1일 부터 1월 31일까지 반복처리
}));

TimeSpan ts = period1.ToTimeSpan(); // 당연히 필요.

기능이 필요할때마다 그때 그때 확정했던 거라, 디자인이 좀 엉망이긴 하지만 ... 날짜 범위가지고 무식한 작업은  안하게 되었으니, 그걸로 만족. 구글코드에 당장 올리긴 힘들고, 일단 바이너리 파일만 사용하실 분은 첨부참조 ... (닷넷 프레임웍 2.0 이상이면 가능)



Vervain.Utils.Time.dll


Vervain.Utils.Time.XML


반응형
2007. 8. 29. 11:23
[System.Threading.Timer] 만약에 특정 시간에 어떠한 작업을 수행할려고 하면 어떻게 해야 될까? 기본적으로 프레임워크상에 Timer Class를 제공하기 때문에 우리는 그다지 크지 않은 노력을 통해 이를 사용할 수 있다. 하지만, 간혹 가다 이러한 Timer를 잘못 사용하는 경우가 있다.

서두에 밝힌 것처럼 매일 "오전 09:00"에 특정 작업을 수행하고 싶다고 할 경우, 어떠한 사람들은 Timer를 사용하여 매 초, 혹은 일정 주기 간격으로 시간을 확인하는 작업을 수행하여 현재 시간과 특정 작업이 일어나야 될 시간을 비교하여 시간이 지났거나, 같을 경우 작업을 실행한다. 하지만 이는 낭비이다. 유저에게 특정 간격으로 Notify를 줄 필요성이 없다면 굳이, 주기적인 Timer를 다시 주기적으로 실행되도록 할 필요는 없다. 이는 꼭 "역전"이라고 표기해야 될 것을 "역전앞"이라고 표기하는 것과 마찬가지이다.

이러한 "낭비"를 없애기 위한 간단한 방법은 간단하게 dueTime을 계산해 주는 방법이 있다.

현재 시간이 09:00이고 특정 작업이 실행되어야 할 시간이 10:00라면 1시간을 dueTime으로 넣어주면 원하는 시간에 특정작업이 한번 실행된다. 만약 24시간 주기로 특정 시간에 특정 작업을 해야 된다면, Timer의 실행 주기를 24시간을 넣어주면 된다.

public delegate void stCallBackDelegate();

    public class ScheduledTimer
    {
        private Timer _timer;

        public ScheduledTimer() { }

        public static TimeSpan GetDueTime(TimeSpan A, TimeSpan B)
        {
            if (A < B)
            {
                return B.Subtract(A);
            }
            else
            {
                return new TimeSpan(24, 0, 0).Subtract(B.Subtract(A));
            }
        }

        public void SetTime(TimeSpan _time, stCallBackDelegate callback)
        {
            if (this._timer != null)
            {
                // Change 매서드 사용 가능.
                this._timer.Dispose();
            }

            TimeSpan Now = DateTime.Now.TimeOfDay;
            TimeSpan DueTime = GetDueTime(Now, _time);
 
            this._timer = new Timer(new TimerCallback(delegate(object _callback)
            {
                ((stCallBackDelegate)_callback)();
            }), callback, DueTime, new TimeSpan(24, 0, 0));
          }
    }
기본적으로 TimeSpan 클래스는 "시간의 길이"를 나타낸다. 즉 9시간에 24시간을 더하면 33시간, 1일 9시간이 된다. DateTime.Now.TimeOfDay는 해당 날짜의 0시부터 현재 시간까지의 길이를 돌려준다. 즉 TimeSpan 클래스를 사용하면서 착각해서는 안되는 부분은 9시간에 24시간을 더하면 24시간 주기로 다시 9시가 될 것이라는 생각이다. 우리가 원하는 스캐쥴러는 이러한 방식이 필요하다. 즉 현재 시간이 오전 11시이고, 특정 작업이 실행되어야 할 시간이 이미 지난 시간이 오전 9시라면, 지연되어야 할 시간은 22시간이다.

작업 예약 시간이 현재 시간보다 나중이면 간단하게 현재 시간에서 예약 시간을 빼면 지연되어야 할 시간이 계산된다. 하지만 반대로 예약 시간이 이미 지난 시간이면, 마이너스 시간 길이가 나오는데, 이를 dueTime에 넣어주면 Timer는 Disable상태가 되어 버린다. 고로 위와 같은 방법으로 지연시간을 계산하여야 한다.
반응형
2007. 8. 29. 09:36
간혹가다 두 개의 독립된 Process간의 통신이 필요한 경우가 있다. 기본적으로 .NET Remoting을 통해 구현을 할수도 있겠지만, 좀 더 간단한 구현을 원할 경우에는 Process 클래스에서 제공하는 표준 입출력 Redirection을 통해 두 개의 프로세스간에 메세지를 교환할 수 있다.

ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = "Program.exe";
psi.RedirectStandardOutput = true;
psi.UseShellExecute = false;

Process TargetProgram = new Process();
TargetProgram StartInfo = psi;
TargetProgram.OutputDataReceived += 
new DataReceivedEventHandler(TargetProgram_OutputDataReceived);

TargetProgram.Start();

//대상 프로세스의 표출 출력을 읽어들인다.
TargetProgram.BeginOutputReadLine();

void TargetProgram_OutputDataReceived(object sender, DataReceivedEventArgs e)
{    
    if (!String.IsNullOrEmpty(e.Data))
    {
         Console.WriteLine(e.Data);
    }
}
// "Program.exe"
Console.WriteLine("Hello :)");
반대의 경우로 송신을 원할 경우에는 대상의 표준 입력을 재설정하고, 표준 입력 스트림에 메세지를 송신하면 된다.
TargetProgram.StartInfo.RedirectStandardInput = true;
StreamWrite sw = TargetProgram.StandardInput;
myStreamWriter.WriteLine("Hello ;)");
반응형
2007. 8. 8. 11:05
System Wake-up Events

원래의 목적은 SetSuspendState를 통해 Standby 상태로 진입시켜 놓고 Wake up Event를 발생시켜 활성상태로 복귀시키는 것이 목적이었다. MSDN에서는 Waitable timer를 통해 이러한 과정을 진행시키는 내용을 명기해 놓았고, 몇몇 자료에서 .NET 환경에서 Waitable timer는 System.Threading.Timer와 대응하기 때문에 이를 통해 Wake up Event를 발생시킬수 있다고 나와있으나, System.Threading.Timer도 API의 Waitable timer도 Standby 상태에서 자동으로 활성상태로 복귀시켜주지 않았다.

일단 주 목적은 모니터를 끄는 것이었기 때문에, 시간 관계상 SendMessage를 통해 모니터를 제어하는 수준에서 처리 하였다.
const int WM_SYSCOMMAND = 0x0112;
const int SC_MONITORPOWER = 0xF170;

const int MONITOR_ON = -1;
const int MONITOR_OFF = 2;
const int MONITOR_STANBY = 1;

[DllImport("user32.dll")]
private static extern int SendMessage(int hWnd, int hMsg, int wParam, int lParam);

/* ... Turn Off ... */

SendMessage(this.Handle.ToInt32(), WM_SYSCOMMAND, SC_MONITORPOWER, MONITOR_OFF);

반응형
prev"" #1 next