# Native Code > برنامه نویسی در Delphi > مباحث عمومی دلفی و پاسکال > آموزش: توابع تبدیل تاریخ با دقت 5000 سال تست شده با تقویم رسمی ایران http://www.time.ir

## یوسف زالی

سلام.
دیدم هنوز برنامه نویسا دنبال این داستان هستند و دیدم که هنوز با تاریخ های کبیسه مشکل دارند.
یک بار برای همیشه قال قضیه رو بکنیم، نه؟!
برای همین این توابع رو برای دوستان آماده کردم.
باشد که با دعای خود موجبات آرامش رفتگان و آسایش ماندگان باشند.

اول از همه این رو در یک یونیت بگذارید:


const
   SolarDayOfWeek: array [0..6] of string = ('شنيه', 
  'يک شنبه', 
  'دوشنبه', 
  'سه شنبه', 
  'چهارشنبه', 
  'پنج شنبه', 
  'جمعه');
  GregorianDayOfWeek: array [0..6] of string = ('Saturday', 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday');

  INVALID_SOLAR_DATE = '1300/01/01';
  INVALID_GREGORIAN_DATE = '1921/03/21';

var
  FormatSetting: TFormatSettings;

type
  TDateBase = (dbSolar, dbGregorian);




function JalCal(JY: Integer; var GY: Integer; var March: integer): boolean;
const
  breaks: Array[1..20] of Integer = (-61, 9, 38, 199, 426, 686, 756, 818,
                                     1111, 1181, 1210, 1635, 2060, 2097,
                                     2192, 2262, 2324, 2394, 2456, 3178);
var
  leapJ, jp, jm, jump, N: Integer;
  j: Integer;
  leap, leapG: Integer;
begin
  GY := JY +621;
  leapJ := -14;
  jp := breaks[1];
  if (JY < jp) or (JY >= breaks[20]) then
    begin
    writeln('error');
    exit;
    end;

  for j := 2 to 20 do
    begin
    jm := breaks[j];
    jump := jm -jp;
    if Jy < jm then
      Break;
    leapJ := leapJ +jump div 33 * 8 +(jump mod 33) div 4;
    jp := jm;
    end;

  N := Jy -jp;
  leapJ := leapJ +N div 33 * 8 +((N mod 33) +3) div 4;
  if(jump mod 33 = 4) and (jump -N = 4)then
    leapJ := leapJ +1;

  leapG := Gy div 4 -(Gy div 100 +1) * 3 div 4 -150;
  March := 20 +leapJ -leapG;
  if (jump -N < 6) then
    N := N -jump +(jump +4) div 33 * 33;
  leap := ((N +1) mod 33 -1) mod 4;
  if leap = -1 then
    leap := 4;

  Result := leap = 0;
end;



initialization
  GetLocaleFormatSettings(LOCALE_SYSTEM_DEFAULT, FormatSetting);
  FormatSetting.ShortTimeFormat := 'HH:MM:SS';
  FormatSetting.ShortDateFormat := 'YYYY/MM/DD';
 // FormatSetting.DecimalSeparator := DECIMAL_DELIMITER;//
 // FormatSetting.ThousandSeparator := THOUSAND_DELIMITER;//


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

تبدیل تاریخ شمسی به میلادی:

function Date_SolarToGregorian(SolarDate: string; CanZero: boolean = false): string;
var
  SYear, SMonth, SDay: integer;
  GYear, GMonth, GDay: integer;
  SIsLeap, GIsLeap: boolean;
  GDate: TDate;
begin
  if CanZero and Date_IsZeroValidDate(SolarDate, dbSolar) then
    begin
    Result := '0000/00/00';
    Exit;
    end;

  if (SolarDate <= INVALID_SOLAR_DATE) or (SolarDate > '3000/12/30') or (length(SolarDate) <> 10) then
    begin
    Result := INVALID_GREGORIAN_DATE;
//    MessageBeep(0);
    exit;
    end;

  if not Date_IsValidDate(SolarDate, dbSolar) then
    begin
    Result := INVALID_GREGORIAN_DATE;
//    MessageBeep(0);
    exit;
    end;

  SYear := StrToInt(Copy(SolarDate, 1, 4));
  SMonth := StrToInt(Copy(SolarDate, 6, 2));
  SDay := StrToInt(Copy(SolarDate, 9, 2));

  SIsLeap := JalCal(SYear, GYear, GDay);

  GMonth := 3;
  GIsLeap := SysUtils.IsLeapYear(GYear);
  GDate := StrToDate(RightStr('000' + IntToStr(GYear), 4) + '/' + RightStr('0' + IntToStr(GMonth), 2) + '/' + RightStr('0' + IntToStr(GDay), 2), FormatSetting);
  GDate := GDate +Date_DaysOfYear(SolarDate, dbSolar) -1;
  Result := DateToStr(GDate, FormatSetting);
end;


تبدیل معکوس با استفاده از ریشه یابی باینری (اینجا) :


function MinimalMoveDateSolar(Dt: string; Step: integer): string;
var
  SYear, SMonth, SDay: integer;
  GYear, GDay: integer;
  DPX: integer;
begin
  SYear := StrToInt(Copy(Dt, 1, 4));
  SMonth := StrToInt(Copy(Dt, 6, 2));
  SDay := StrToInt(Copy(Dt, 9, 2));

  repeat
    DPX := Date_DaysPerYear(SYear, dbSolar);
    if Step < DPX then
      break;
    dec(Step, DPX);
    inc(SYear);
  until false;

  repeat
    DPX := Date_DaysPerMonth(SYear, SMonth, dbSolar);
    if Step < DPX then
      break;
    dec(Step, DPX);
    inc(SMonth);
    if SMonth > 12 then
      begin
      SMonth := 1;
      inc(SYear);
      end;
  until false;

  inc(SDay, Step);
  if SDay > Date_DaysPerMonth(SYear, SMonth, dbSolar) then
    begin
    SDay := 1;
    inc(SMonth);
    if SMonth > 12 then
      begin
      SMonth := 1;
      inc(SYear);
      end;
    end;

  Result := RightStr('000' + IntToStr(SYear), 4) + '/' + RightStr('0' + IntToStr(SMonth), 2) + '/' + RightStr('0' + IntToStr(SDay), 2);
end;

function Date_GregorianToSolar(GregorianDate: string): string;
var
  S, S1, S2: string;
  G, G1, G2: string;
  LoopCounter: integer;
begin
  if (GregorianDate <= INVALID_GREGORIAN_DATE) or (GregorianDate > '3622/03/20') or (length(GregorianDate) <> 10) then
    begin
    Result := INVALID_SOLAR_DATE;
//    MessageBeep(0);
    exit;
    end;

  if not Date_IsValidDate(GregorianDate, dbGregorian) then
    begin
    Result := INVALID_SOLAR_DATE;
//    MessageBeep(0);
    exit;
    end;

  S1 := IntToStr(StrToInt(Copy(GregorianDate, 1, 4)) -622) + '/01/01';
  S2 := IntToStr(StrToInt(Copy(GregorianDate, 1, 4)) -621) + '/12/29';

  G1 := Date_SolarToGregorian(S1);
  G2 := Date_SolarToGregorian(S2);

  while G1 > GregorianDate do
    begin
    S1 := Date_MoveDate(S1, -100, dbSolar);
    G1 := Date_SolarToGregorian(S1);
    end;

  while G2 < GregorianDate do
    begin
    S2 := Date_MoveDate(S2, 100, dbSolar);
    G2 := Date_SolarToGregorian(S2);
    end;

  LoopCounter := 0;

  if G1 = GregorianDate then
    Result := S1

  else if G2 = GregorianDate then
    Result := S2

  else
    begin

    repeat
      S := MinimalMoveDateSolar(S1, round(Date_DaysBetween(S1 ,S2, dbSolar) / 2));
      G := Date_SolarToGregorian(S);

      if G = GregorianDate then
        begin
        Result := S;
        break;
        end

      else if G > GregorianDate then
        S2 := S

      else if G < GregorianDate then
        S1 := S;

      inc(LoopCounter);
    until LoopCounter >= 13;

    if LoopCounter >= 13 then
      begin
      Result := INVALID_GREGORIAN_DATE;
//      MessageBeep(0);
      end
    else
      Result := S;

    end;
end;


توابع دیگر:


function Date_DaysOfYear(Dt: string; DateBase: TDateBase): integer;
var
   SMonth, SDay: integer;
begin
  if DateBase = dbSolar then
    begin
    SMonth := StrToInt(Copy(Dt, 6, 2));
    SDay := StrToInt(Copy(Dt, 9, 2));

    case SMonth of
      1: Result := SDay;
      2: Result := SDay +31;
      3: Result := SDay +62;
      4: Result := SDay +93;
      5: Result := SDay +124;
      6: Result := SDay +155;
      7: Result := SDay +186;
      8: Result := SDay +216;
      9: Result := SDay +246;
     10: Result := SDay +276;
     11: Result := SDay +306;
     12: Result := SDay +336;
    end;
    end

  else
    Result := DayOfTheYear(StrToDate(Dt, FormatSetting));
end;



function Date_DaysPerYear(Y: integer; DateBase: TDateBase): integer;
begin
  Result := DaysPerYear[Date_IsLeapYear(Y, DateBase)];
end;



function Date_DaysPerMonth(Y, M: integer; DateBase: TDateBase): integer;
begin
  if DateBase = dbSolar then
    case M of
      1..6: Result := 31;
      7..11: Result := 30;
      12: Result := IfThen(Date_IsLeapYear(Y, dbSolar), 30, 29);
    end

  else
    Result := MonthDays[(M = 2) and SysUtils.IsLeapYear(Y), M];
end;



function Date_DaysBetween(Dt1, Dt2: string; DateBase: TDateBase): integer;
var
  SYear1: integer;
  SYear2: integer;
  i, Day: integer;
  X1, X2: integer;
begin
  if DateBase = dbSolar then
    begin
    SYear1 := StrToInt(Copy(Dt1, 1, 4));
    SYear2 := StrToInt(Copy(Dt2, 1, 4));

    Day := 0;
    for i := SYear1 +1 to SYear2 -1 do
      Day := Day +Date_DaysPerYear(i, dbSolar);

    X1 := Date_DaysOfYear(Dt1, dbSolar);
    X2 := Date_DaysOfYear(Dt2, dbSolar);
    Result := Day + X2 -X1 +IfThen(SYear1 = SYear2, 0, Date_DaysPerYear(SYear1, dbSolar));
    end

  else
    Result := DaysBetween(StrToDate(Dt1, FormatSetting), StrToDate(Dt2, FormatSetting));
end;



function Date_IsLeapYear(Y: integer; DateBase: TDateBase): boolean;
var
  DD, YY: integer;
begin
  if DateBase = dbSolar then
    Result := JalCal(Y, YY, DD)
  else
    Result := SysUtils.IsLeapYear(Y);
end;



function Date_MoveDate(Dt: string; Step: integer; DateBase: TDateBase): string;
var
  D: TDate;
begin
  if DateBase = dbSolar then
    Dt := Date_SolarToGregorian(Dt);

  D := StrToDate(Dt, FormatSetting) +Step;
  Dt := DateToStr(D, FormatSetting);

  if DateBase = dbSolar then
    Dt := Date_GregorianToSolar(Dt);

  Result := Dt;
end;



function Date_DifDate(Dt1, Dt2: string; DateBase: TDateBase): integer;
begin
  if DateBase = dbSolar then
    begin
    Dt1 := Date_SolarToGregorian(Dt1);
    Dt2 := Date_SolarToGregorian(Dt2);
    end;

  Result := DaysBetween(StrToDate(Dt1, FormatSetting), StrToDate(Dt2, FormatSetting));
end;



function Date_IsValidDate(Dt: string; DateBase: TDateBase): boolean;
var
  DD, MM, YY: integer;
begin
  if length(Dt) <> 10 then
    begin
    Result := false;
    exit;
    end;

  DD := StrToInt(Copy(Dt, 9, 2));
  MM := StrToInt(Copy(Dt, 6, 2));
  YY := StrToInt(Copy(Dt, 1, 4));

  if DateBase = dbSolar then
    Result := (MM in [1..12])
              and (
                   (MM in [1..6]) and (DD in [1..31]))
                   or
                   ((MM in [7..11]) and (DD in [1..30]))
                   or
                   ((MM = 12) and (DD in [1..IfThen(Date_IsLeapYear(YY, dbSolar), 30, 29)])
                   )

  else
    Result := IsValidDate(YY, MM, DD);
end;



function Date_IsZeroValidDate(Dt: string; DateBase: TDateBase): boolean;
var
  DD, MM, YY: integer;
begin
  if length(Dt) <> 10 then
    begin
    Result := false;
    exit;
    end;

  DD := StrToInt(Copy(Dt, 9, 2));
  MM := StrToInt(Copy(Dt, 6, 2));
  YY := StrToInt(Copy(Dt, 1, 4));

  if DateBase = dbSolar then
    Result := ((DD = 0) and (MM in [0..12]))
              or
              ((MM = 0) and (DD in [0..31]))
              or
              ((YY = 0) and (DD in [0..31]) and (MM in [0..12]))

  else
    Result := false;
end;



function Date_FirstDayOfYear(Year: integer): string;
begin
  result := IntToStr(Year) + '/01/01';
end;



function Date_LastDayOfYear(Year: integer; DateBase: TDateBase): string;
begin
  if Date_IsLeapYear(Year, DateBase) then
    Result := IntToStr(Year) + '/12/30'
  else
    Result := IntToStr(Year) + '/12/29';
end;



function Date_CurrentDate(DateBase: TDateBase = dbSolar): string;
begin
  if DateBase = dbSolar then
    Result := Date_GregorianToSolar(DateToStr(Date, FormatSetting))
  else
    Result := DateToStr(Date, FormatSetting);
end;



function Date_DateToString(Dt: TDateTime; DateBase: TDateBase): string;
begin
  if DateBase = dbSolar then
    Result := Date_GregorianToSolar(DateToStr(Dt, FormatSetting))
  else
    Result := DateToStr(Dt, FormatSetting);
end;



function Date_StringToDate(Dt: string; DateBase: TDateBase): TDateTime;
begin
  if DateBase = dbSolar then
    Result := StrToDate(Date_SolarToGregorian(Dt), FormatSetting)
  else
    Result := StrToDate(Dt, FormatSetting);
end;


دوستان من این توابع رو از یونیتی که نوشته بودم و 12000 خط داره کپی کردم. ممکنه بعضی جاهاش رو یادم رفته باشه.
اگر جایی ارور داد بگید تا بگذارم.

امیدوارم که دوستان یادگاری از من داشته باشند.
موفق باشید.

----------


## fahimi

سلام 
کدام یک از تابع بالا تاریخ شمسی را برمی گرداند

----------


## fahimi

پیدا کردم Date_GregorianToSolar
در ضمن پست بالا بصورت یونیت ضمیمه نمودم

----------


## kamran749

> پیدا کردم Date_GregorianToSolar
> در ضمن پست بالا بصورت یونیت ضمیمه نمودم


با سلام و تشکر
لطفا طريقه فراخواني هر کدام از تاريخها را بر روي کپشن يک ليبل بنويسيد.
ممنون :تشویق:

----------


## یوسف زالی

فایل یونیت یکمی اصلاح شد.
طریقه فراخوانیش خیلی ساده هست. شما کجاش مشکل داری؟ بگو توضیح بدم.

----------


## kamran749

> فایل یونیت یکمی اصلاح شد.
> طریقه فراخوانیش خیلی ساده هست. شما کجاش مشکل داری؟ بگو توضیح بدم.


سلام
طريقه فراخواني تاريخ شمسي(Date_GregorianToSolar) را پيدا نمودم، اما بقيه توابع را نمي دانم چه هستند و چگونه فراخواني ميشوند.منجمله اگر بخواهيم تاريخ شمسي به صورت حروف باشد ، بايد چه تابعي را فراخواني کنيم يا تاريخ قمري ...؟ :متعجب:

----------


## یوسف زالی

ما همین جوریش هم باید بشینیم تا ببینیم ماه رو دیدن یا نه تا روزه بگیریم یا نه،
هیچ تاریخ قمری ای دقیق نیست. تنها باید گذشته اون رو در دیتابیس گشت.
در خصوص فارسی شدن، این توابع رو اضافه کنید:

function Date_SolarMonthName(Month: integer): string;
begin
  case Month of
    1: Result := 'فروردین';
    2: Result := 'اردیبهشت';
    3: Result := 'خرداد';
    4: Result := 'تیر';
    5: Result := 'مرداد';
    6: Result := 'شهریور';
    7: Result := 'مهر';
    8: Result := 'آبان';
    9: Result := 'آذر';
   10: Result := 'دی';
   11: Result := 'بهمن';
   12: Result := 'اسفند';
  end;
end;

function Date_SolarFullName(Dt: string): string;
var
  YY, MM, DD: string;
begin
  DD := Copy(Dt, 9, 2);
  MM := Copy(Dt, 6, 2);
  YY := Copy(Dt, 1, 4);

  Result := DD + ' ' + Date_SolarMonthName(StrToInt(MM)) + ' ' + YY;
end;



مهم بیس داستانه، بقیش به راحتی توسعه پذیره.

----------


## kamran749

> ما همین جوریش هم باید بشینیم تا ببینیم ماه رو دیدن یا نه تا روزه بگیریم یا نه،
> هیچ تاریخ قمری ای دقیق نیست. تنها باید گذشته اون رو در دیتابیس گشت.
> در خصوص فارسی شدن، این توابع رو اضافه کنید:
> 
> function Date_SolarMonthName(Month: integer): string;
> begin
>   case Month of
>     1: Result := 'فروردین';
>     2: Result := 'اردیبهشت';
> ...


سلام دوست عزيز
به فکر ما مبتدي ها هم باش.من اين کد را کجا بگذارم و  چگونه آنرا فراخواني کنم تا تاريخ شمسي را به صورت حروف به من برگرداند. :متعجب:  من  مي خواهم تاريخ اينگونه نوشته شود.
براي مثال: بيست و پنجم ، خرداد ، هزار و سيصد و نود و دو
يا مثلا: بيست و پنجم ، خرداد ، 1392
قبلا  چندين بار در جاهاي مختلف درخواست کردم ولي همه به اين طرف و آن طرف پاس  داده اند و به غير از يک کد که با سالهاي کبيسه مشکل دارد ، چيزي گيرم  نيامد.

----------


## SayeyeZohor

ShowMessage(Date_SolarFullName('1392/02/02'));

----------


## eshge89

سلام دوست عزيز خوبي؟
ممنونم  از توابعي كه گذاشتين 
حالا مي شه بگين با كدوم يكي از اين توابع  ميشه يك عدد را با تاريخ شمسي كم يا جمع كرد؟؟واضحتر توضيح بدين 
يا در صورت امكان يه نمونه برنامه در اين خصوص بذارين 
با تشكر 
منتطرتون هستم 
خيلي واجبه دوست عزيز

----------


## eshge89

سلام مهندس - من همچنان منتظر پاسختون هستم*You-Seeمهندس* - ممنون مي شم سريعتر راهنماييم كنيد

----------


## یوسف زالی

توابع بالا رو که بخونین همه چیز واضحه.
برای مثال افزودن یک عدد به تاریخ شمسی:

NewDate := Date_MoveDate('1392/04/25', 5, dbSolar);

----------


## eshge89

مهندس من زياد با دلفي كار نكردم ميشه زحمت بكشيد و برام يه نمونه برنامه بدين ؟؟؟
نگاه كردم اما چيزي متوجه نشدم .
ميشه زودتر بدين ؟؟

----------


## یوسف زالی

دوست عزیز شما شروع کن هر جا گیر کردی کمک می کنیم.
دستوری که گذاشتم به حدی واضحه که نیازی به توضیح نداره.
بسم الله.. استارت بزن سوال داشتی بپرس.

----------


## eshge89

من تمام توابع رو تو قسمت كد نويسي فرمم اضافه كردم اما ارور داد
نتونستم استفاده كنم
ميشه لطف كنيد يه نمونه برنامه كوچولو در اختيارم بذاريد؟؟؟
خيلي لازم دارم

----------


## ELI994

با سلام و تشکر از زحماتی که کشیدین 
من یونیتی رو که شما زحمتش رو کشیده بودین رو به پروژه ام اضافه کردم ولی این پیغام ها رو دریافت کردم 
[C++‎ Error] AU.cpp(8): E2209 Unable to open include file 'U30DateUnit.hpp'
 

[C++‎ Error] AU.cpp(61): E2268 Call to undefined function 'Date_SolarFullName'


#pragma hdrstop
#include "AU.h"
#include "B.hpp"
#include "U30DateUnit.hpp"
با توجه با اینکه این یونیت هم به فرم اصلی اضافه شده 
لطفا راهنمایی بفرمائید

----------


## یوسف زالی

سلام.
فکر می کنم که در قسمت Interface اعلان این تابع رو نگذاشتید.
اگر همچنان مشکل  داشتید نمونه سورس رو ضمیمه کنید نگاه کنم.

----------


## eshge89

دوست عزيز من همچنان منتظر راهنمايي هاي شما هستم

----------


## ELI994

من تو بیلدر اینرو اضافه کردم

----------


## یوسف زالی

یکمی زحمت بدید به خودتون،
آقا/خانم عشق 89 :
شما نه می گی ارورت چیه نه اصلا کدی گذاشتی، این که نمی شه.

آقا/خانم الی 994 :
جواب شما که ارتباطی به حرف من نداشت. سورس نذاشتید!

به هر حال این نمونه برنامه کوچیک رو براتون می گذارم. امیدوارم راتون بندازه.
موفق باشید.

----------


## ELI994

من همیشه تو یه برنامه دیگه اول کدی رو که بلد نیستم رو تست می کنم بعد به برنامه اصلی اضافه می کنم 
این هم فایل تست هستش 
Project.rar
ممنون از اینکه توجه فرمودین 
فقط اگه امکانش باشه نحوه پیاده سازیش رو بهم بگین

----------


## یوسف زالی

عزیز من، گفتم که سورس بدید.
از طرفی نمونه برنامه هم گذاشتم.
با سی پلاس پلاس برنامه دادید واسه تست یونیت دلفی؟!
این فایلیه که توش ایناست:

//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop
//---------------------------------------------------------------------------
USEFORM("D:\Example\AU.cpp", Form1);
//---------------------------------------------------------------------------
WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
        try
        {
                 Application->Initialize();
                 Application->CreateForm(__classid(TForm1), &Form1);
                 Application->Run();
        }
        catch (Exception &exception)
        {
                 Application->ShowException(&exception);
        }
        catch (...)
        {
                 try
                 {
                         throw Exception("");
                 }
                 catch (Exception &exception)
                 {
                         Application->ShowException(&exception);
                 }
        }
        return 0;
}
//---------------------------------------------------------------------------


من چی این رو باید ببینم؟
دوست عزیز شما مبانی برنامه نویسی رو فکر می کنم زیاد بلد نیستی، پیشنهاد من اینه که اول یک کتاب از مبانی پیدا کنی و چند تا برنامه کوچیک با دلفی بنویسی، بعد در خدمتیم.
موفق باشی.

----------


## ELI994

من اولش هم بهتون گفتم که برنامه من توی سی بیلدر هستش. 
آقا/خانم الی 994 :
جواب شما که ارتباطی به حرف من نداشت. سورس نذاشتید!

این جواب رو به من دادین . ماشالله مجال حرف زدن که به آدم نمیدین 
من کمکی که ازتون خواستم این بود که یونیتتون تو سی بیلدر ارور میده همین بود جرمم

----------


## یوسف زالی

در پست شماره 16 اشاره ای به این موضوع نشد.
در پست 19 هم گفتید در بیلدر اضافه کردم.
شما می تونید در نوت پد هم برنامه نویسی کنید. من که نمی دونم در بیلدر می شه دلفی کد زد و کامپایل کرد یا نه (تا جایی که یادمه می شه!)
بنابراین شما باید زبان مورد استفاده رو می گفتید.
برای این که از این توابع در زبان خودتون استفاده کنید باید یک نفر زحمت DLL کردن این توابع رو براتون بکشه.
موفق باشید.

----------


## BORHAN TEC

سلام



> برای این که از این توابع در زبان خودتون استفاده کنید باید یک نفر زحمت DLL کردن این توابع رو براتون بکشه.


نیازی به این کار نیست. C++‎‎ Builder توانایی Compile و استفاده از یونیت های دلفی را دارد.  :کف کرده!:  من یک پروژه نمونه را در C++‎‎ Builder ایجاد کرده ام که می تواند از یونیت U30DateUnit.pas استفاده کند. این پروژه نمونه با C++‎‎ Builder XE4 تست شده است که آنرا ضمیمه کرده ام. انجام این کار حتی در نسخ فسیل شده C++‎‎ Builder هم امکان پذیر است. در ضمن بنده قبلاً ویدئویی را در خصوص استفاده از یونیتهای دلفی در BCB ایجاد کرده ام که فیلم آن در آدرس زیر قرار دارد:
http://www.irstu.com/?p=8490
موفق باشید...

----------


## hector2000

من این تابع را نوشتم که خیلی سریع و دقیق تاریخ میلادی را به شمسی تبدیل می کند


function MiladiToShamsi(N:tdate):string;

const
 W : array[1..7] of widestring = ('یکشنبه','دوشنبه','سه شنبه','چهارشنبه','پنجشنبه','ج  عه','شنبه');
 Mon : array[1..12] of widestring = ('فروردین', 'اردیبهشت', 'خرداد', 'تیر', 'مرداد', 'شهریور', 'مهر', 'آبان', 'آذر', 'دی', 'بهمن', 'اسفند');
 var
 days,Y,D,M:integer;
 begin

  days:= DaysBetween(N,EncodeDate(1900,1,1));
   days :=days + 2112;
    Y := 1273;
    M := 0;
    D := 0;

    Y := Y + Trunc(days / 12053) * 33;
    days := days mod 12053;

    Y := Y + Trunc(days / 1461) * 4;
    days := days mod 1461;

    if (days = 1460)then
    begin
        Y := Y + 3;
        days := 365;
    end
    else
    begin
  Y := Y + Trunc(days / 365);
    days := days mod 365;
  end;



    if (days < 186)then
    begin
        M := Trunc(days / 31) + 1;
        D := days mod 31 + 1;
    end
    else
    begin
        M := Trunc((days - 186) / 30) + 7;
        D := (days - 186) mod 30 + 1;
    end;
  result:= inttostr(Y)+' ' + Mon[M] + ' ' + Inttostr(D)+ ' ' + W[DayOfWeek(N)];
 end;



طریقه استفاده:

Label1.caption:=MiladiToShamsi(date);

----------


## یوسف زالی

این قطعه کد در بازه زمانی کوتاه معقول به نظر می رسه.
بنا به دلایلی که در استفاده از کامپوننت شمسی میلادی استفاده کردم، اولین روز شمسی رو 01/01/1300 قرار دادم.
از همین تاریخ شروع می کنیم به مقایسه:

2256/03/20	MiladiToShamsi = 1634/12/30	Date_GregorianToSolar = 1635/01/01
ta
2257/03/20	MiladiToShamsi = 1635/12/29	Date_GregorianToSolar = 1635/12/30

2289/03/20	MiladiToShamsi = 1667/12/30	Date_GregorianToSolar = 1668/01/01
ta
2290/03/20	MiladiToShamsi = 1668/12/29	Date_GregorianToSolar = 1668/12/30

2322/03/21	MiladiToShamsi = 1700/12/30	Date_GregorianToSolar = 1701/01/01
ta
2323/03/21	MiladiToShamsi = 1701/12/29	Date_GregorianToSolar = 1701/12/30

2355/03/21	MiladiToShamsi = 1733/12/30	Date_GregorianToSolar = 1734/01/01

همون طور که می بینید در تاریخ های بالا (و تمام تاریخ های بین اون، و ایضا تاریخ های دیگه ای که دیگه ادامه ندادم) خروجی برنامه شما با برنامه من فرق داره.
تاریخ های بالا در سایت www.time.ir تست شد و خروجی برنامه شما اشتباه و خروجی برنامه من درست بود.

همون طور که گفتم در بازه قبل از 1634/12/30 شمسی برنامه شما درست کار می کنه. ولی بعد از این تاریخ اشتباهات شروع می شه..

----------


## MohsenB

سلام

باتشکر از یوسی جان و با اجازه ایشون

اول اینکه تغییراتی که برای اجرا توی فری پاسکال ( + لازاروس ) لازمه رو انجام دادم و دومم یه مثال با دلفی و لازاروس اضافه کردم . امیدوارم که مورد استفاده قرار بگیره .


موفق باشید

----------


## khoshblagh

با سلام خدمت اساتید محترم 
میخواهم با عبارت زیر تاریخ فرضا امروز را در یک متغیر قرار داده و از یک فیلد که در آن تاریخ میباشد کسر نمایم و نتیجه را که قطعا تعداد روزهای متفاوتی میباشد در فیلدی دیگری وارد نمایم . ولی عبارت نوشته شده دچار خطای سینتکس میشود . چرا؟ 
   strEmroz:=Date_CurrentDate(dbSolar);
  cmdUpdateRozMondeh.CommandText:='UPDATE tblTazmin SET RozMondeh='+
               Date_DaysBetween(+'TarikhPayan',strEmroz,dbSolar) +
              ' WHERE (NoaZmanat = 0) AND (VazTazmin = 0) OR (VazTazmin = 1);

----------


## یوسف زالی

شما نمی تونی از توابع دلفی در اس کیو ال استفاده کنی.

Date_DaysBetween(+'TarikhPayan',strEmroz,dbSolar)

اینجا شما داری رشته رو مقایسه می کنی.
قبلش باید بریزی در یک متغیر، بعد با توابع دلفی حساب کتاب کنید، بعدش که Date_DaysBetween مقدارش رو داد، ازش استفاده کنید.

----------


## BORHAN TEC

با سلام،
به نظرم این یونیت یک ایراد اساسی داره و اون هم در تبدیلات تاریخ هست. در سیستم میشه تنظیمات تاریخ رو طوری عوض کرد که مثلاً به جای / در تاریخها از - و یا کاراکترهای دیگه استفاده بشه و یا اینکه جای روز و ماه و سال رو جابجه کنیم و ... .توی این یونیت برای تبدیلات تاریخ رو به صورت رشته میگیره که کار پردازش رو به شدت سخت میکنه و گاهی غیر ممکن میکنه و فکر می کنم استفاده از این روش اصلاً کار درستی نباشه. به نظر من هرجایی که کار تبدیل تاریخ (از میلادی به شمسی و یا هر مدل دیگری) انجام میشه ورودی تابع باید از نوع TDateTime و امثالهم باشه و نه از نوع رشته.  :متفکر:

----------


## یوسف زالی

ورودی و خروجی برای سادگی رشته گرفته شده. خیلی از مواقع در دیتابیس ها و البته گزارشات دسترسی به نوع استاندارد وجود نداره. البته اگر هم داشته باشه برای تبدیل به شمسی باز باید روز و ماه و سالش در بیاد. کار با رشته ساده تره، اما می تونستیم مثلا با نوع Word هم کار کنیم. اساس کار یک سری تبدیلات بر اساس اعداده، ورودی و خروجی چندان اهمیتی نداره، تو سرعت هم به چشم نمیاد  :چشمک:

----------


## BORHAN TEC

> ورودی و خروجی برای سادگی رشته گرفته شده. خیلی از مواقع در دیتابیس ها و البته گزارشات دسترسی به نوع استاندارد وجود نداره. البته اگر هم داشته باشه برای تبدیل به شمسی باز باید روز و ماه و سالش در بیاد. کار با رشته ساده تره، اما می تونستیم مثلا با نوع Word هم کار کنیم. اساس کار یک سری تبدیلات بر اساس اعداده، ورودی و خروجی چندان اهمیتی نداره، تو سرعت هم به چشم نمیاد


توضیح دادی، رفاقتمون سر جاش ولی از اونجایی که توی مسائل فنی خیلی جدی هستم توضیحاتت نتونست من رو قانع کنه.  :قلب: چون شرایط مختلفی وجود داره حداقل برای تبدیل میلادی به شمسی ورودی باید به صورت TDateTime باشه و بجای استفاده از پردازش رشته برای بدست آوردن ماه، سال، و روز باید حتماً و حتماً از توابع داخل یونیت DateUtils که شامل توابع YearOf و MonthOf و DayOf هست استفاده بشه و استفاده از کد به کار رفته زیر اصلاً درست نیست:
function Date_IsValidDate(Dt: string; DateBase: TDateBase): boolean;var
  DD, MM, YY: integer;
begin
  if length(Dt) <> 10 then
    begin
    Result := false;
    exit;
    end;


  DD := StrToInt(Copy(Dt, 9, 2));
  MM := StrToInt(Copy(Dt, 6, 2));
  YY := StrToInt(Copy(Dt, 1, 4));


  // ...
end;



در حالت کلی برای انجام این تبدیلات استفاده از پردازش رشته و استفاده از تابع Copy و نظایر آن اشتباه ترین کار ممکن است. مثلاً در کد بالا فرض کن که تاریخ به صورت 2012/6/1 باشه و پشت ماه و روز عدد 0 نباشه. خوب حالا چه مشکلی به وجود میاد؟!  :متفکر:  درسته در بالا طول 10 چک شده ولی چرا موقعی که صفر پشت ماه یا روز نوشته نشه تابع نباید درست کار کنه؟ واقعاً چرا؟

----------


## یوسف زالی

این یونیت یک یونیت قدیمی برای یکی از کامپوننت هام هست. در اون جا هم کنترل های لازم همگی انجام شده و کاربر نمی تونه خارج از قواعد چیزی بزنه، سرسختیت همیشه برام مهم و ارزشمند بوده و هست. بعضی از کدهایی که به نظر بی مورد یا عجیب میاد، در اصل کات شده ی کد اصلی من بود. بعضی جاها مثلا چک شده تا صفر بودن تاریخ (!!) بررسی بشه، دلیلش هم چیزی بود که بیان کردم.
کد به طور صحیح کار می کنه، و می شه ازش استفاده کرد، اما بهینه نیست. مخصوصا در استفاده از تبدیل معکوس با استفاده از روش ریشه یابی دودویی.
خیلی خوبه که گیر بدی، باعث افزایش دقت من هم می شه.
اصلا یکی از موارد دیگه ای که باید در این کد رعایت بشه، FormatSetting هست.
مواردی که گوشزد کردی، به جاست.
مهم ترین دلیلی که این یونیت اینجا گذاشته شد، بحث آموزشی قضیه هست، و مهم تر از اون این که مشکل همیشگی با تاریخ های کبیسه حل بشه. باقی توابع و ورودی ها همگی قابل بازنویسی هستند.
از این که می بینم کدهای من توسط عزیزان حرفه ای تر از من بررسی می شه و نقطه نظراتشون رو می گن، باعث خوشحالی منه.
کارت در اومد، باید کدی رو که از نظر خودت درسته، یا از اون بهتر، اصلاح شده یونیت من رو بگذاری اینجا  :لبخند گشاده!: 
خوبت بشه!

----------


## BORHAN TEC

> از این که می بینم کدهای من توسط عزیزان حرفه ای تر از من بررسی می شه و نقطه نظراتشون رو می گن، باعث خوشحالی منه.


امیدوارم که منظورت من نبوده باشم. شما خودت استاد ما هستی.  :قلب: 



> اصلا یکی از موارد دیگه ای که باید در این کد رعایت بشه، FormatSetting هست.


کاستی های مختلفی داره. مثلاً موقعی که یک تاریخ رو به صورت رشته به تابع میدیم کاربر حتماً در پارامتر دیگری از همون تابع باید فرمت تاریخ رو وارد کنه و ... .



> کارت در اومد، باید کدی رو که از نظر خودت درسته، یا از اون بهتر، اصلاح شده یونیت من رو بگذاری اینجا 
> خوبت بشه!


باشه، این پروژه که دارم روش کار می کنم تموم شد این یونیت رو تا جایی که سوادم برسه اصلاح میکنم.  :لبخند گشاده!:

----------


## یوسف زالی

> مثلاً موقعی که یک تاریخ رو به صورت رشته به تابع میدیم کاربر حتماً در پارامتر دیگری از همون تابع باید فرمت تاریخ رو وارد کنه


این کاستی نیست، اتفاقا قدرته، کاربر می تونه با یک تابع هم کارای شمسی کنه هم میلادی، به طور مثال انتقال تاریخ به چند رو بعد / قبل، شمسی با میلادی فرق داره. از طرفی پیش فرض داره به این معنی که برنامه نویس هیچی هم نداد، نداد.

منتظر کدت هستم، بالاخره دو تا مغز دو تا فکر دارند که مسلما از یک فکر بهتره.
 :چشمک:

----------


## ariopax

سلام 
آقا این یونیت رو چطور میشه تبدیلش کرد به یه تقویم .مثل Calender خود دلفی .ویا دیگر کامپوننتها

----------


## یوسف زالی

سلام. من این کار رو قبلا ها برای شرکتی که توش کار می کردم کرده بودم، باید کامپوننت براش بنویسی و توابع رو در اون بگنجونی، یک دموی خیلی خلاصه روی دلفی هفت ازش دارم که براتون می گذارم.

----------


## ariopax

باتشکرازشما.
فکر میکنم اشتباه شده .چون این فیلم آموزش اینتراوبه.اگه امکان داره دموی کامپوننت رو یه باردیگه آپلودکنید.
باتشکر

----------


## یوسف زالی

لینک ها تصحیح شد.

----------


## hadisalahi2

یوسف جان من توی این یونیت به یک مشکل خوردم
متاسفانه اختلاف بین دو تاریخ رو درست برام محاسبه نمیکنه
ولی وقتی با XCalendarمحاسبه کردم جواب درست رو بهم داد

میشه یک نمونه خودت تست کنی
من اختلاف دو تاریخ رو به رو میخواستم که اختلاف محاسبه خیلی زیاد بود
مثلا حدود 200 روز اشتباه محاسبه کرده بود

ممنونم
یا حق

----------


## یوسف زالی

تاریخ هات رو بگذار لطفا. احتمالا فرمت اشتباه دادی

----------


## hadisalahi2

دقیقا تاریخ هایی که گذاشته بودم رو یادم نمیاد
چون عجله داشتم این قسمتش رو با XCalenar  انجام دادم
ولی مثلا این دو تا تاریخ رو چک کن و روش فراخوانی تابع رو هم بی زحمت بنویس

1392/01/31
1393/08/10

یکی از خوبیهای کدی که نوشتی اینه که روی تاریخ های 31 و 30 ماهها گیر نمیده
در صورتی که Xcalenadr با این موضوع مشکل داره

----------


## یوسف زالی

ShowMessage(IntToStr(Date_DifDate('1392/01/31', '1393/08/10', dbSolar)));

----------


## یوسف زالی

این طور اصلاح کنید:


function Date_DifDate(Dt1, Dt2: string; DateBase: TDateBase): integer;
var
  D1, D2: TDate;
begin
  if DateBase = dbSolar then
    begin
    Dt1 := Date_SolarToGregorian(Dt1);
    Dt2 := Date_SolarToGregorian(Dt2);
    end;


  D1 := StrToDate(Dt1, FormatSetting);
  D2 := StrToDate(Dt2, FormatSetting);
  Result := abs(DaysBetween(D1, D2)) * IfThen(D1 < D2, 1, -1);
end;

----------


## hadisalahi2

این کد تست شده هستش دیگه؟
آیا قبلا مشکل داشت یا من اشتباه فراخوانی کرده بودم؟

----------


## یوسف زالی

یکم فرق کرده. تو پروژه های من داره کار می کنه. دوس سالی هم هست ریپورتی نداشتم.

----------


## rezamahdizadeh

سلام
آیا کد تبدیلهای تاریخ به همدیگر در SQL Server با همین الگوریتم و دقت را نیز دارید؟
جناب You-See این کامپوننت ورود تاریخ که در کلیپی در پست 38 لینک داده اید خودتان نوشته اید؟

----------


## یوسف زالی

کد تبدیل در اس کیو ال رو ندارم ولی می شه به راحتی تبدیلش کرد. زیاد سخت نیست.
باید تابع رو تبدیل به تابع اسکالر در اس کیو ال کنید.
بله. اون کامپوننت یکی از کارهای من هست.

----------


## hadisalahi2

سلام
من چند روز پیش داشتم یک تاریخ رو تبدیل میکردم که متاسفانه خطا داد

من تاریخ 20 فرودین 94 رو میخواستم 7 روز کم کنم
اما متاسفانه پیام خطای Data is invalid رو داد
میشه یک چک بفرمایید

اینم کدش: 
 Date2:=IncDayShamsi(PublicDate,-7);

PublicDate هم توی تاریخ 1394/01/20 بود

----------


## یوسف زالی

سلام.
94/01/13
مشکلی نبود. البته با اسامی توابع من، اون اسم تابع رو خودتون بازنویسی کردید؟ کدش درسته؟

----------


## hadisalahi2

نه یوسف جان
دقیقا اسم تابعی هستش که توی یونیت شما وجود داره

Function IncDayShamsi(DateValue:String;IncValue:Shortint):S  tring;





> 94/01/13
> مشکلی نبود. البته با اسامی توابع من، اون اسم تابع رو خودتون بازنویسی کردید؟ کدش درسته؟


این تاریخ مشکل نیست
تاریخ 1394/01/20 مشکل داره
یعنی به این تاریخ گیر میده و این خطا رو میده Data is invalid

من هیچ تغییری در کد شما ندادم
مگه اینکه جدیدا شما تغییری داده باشی که من اون کد رو ندارم

----------


## یوسف زالی

می شه کدی که داری رو بگذازی؟
من همچین اسمی ندارم شاید دوستان زحمت کشیدن توسعش دادن.

----------


## hadisalahi2

خدمت داش یوسف گل

Function  IncMonthShamsi(DateValue:String;IncValue:Shortint)  :String;
 var ConvertDate:String[10];
 Begin
  ConvertDate:=Date_SolarToGregorian(DateValue);
  ConvertDate:=DateToStr(IncMonth(StrToDate(ConvertD  ate),IncValue));
  ConvertDate:=Date_GregorianToSolar(ConvertDate);
  Result:=ConvertDate;
 End;
//QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ  QQQQQQQQQQQQQQQQQQQQQQQQQQQQ
Function  IncDayShamsi(DateValue:String;IncValue:Shortint):S  tring;
 var ConvertDate:String[10];
 Begin
  ConvertDate:=Date_SolarToGregorian(DateValue);
  ConvertDate:=DateToStr(IncDay(StrToDate(ConvertDat  e),IncValue));
  ConvertDate:=Date_GregorianToSolar(ConvertDate);
  Result:=ConvertDate;
 End;

----------


## یوسف زالی

با این تست کن:

function Date_MoveDate(Dt: string; Step: integer; DateBase: TDateBase): string;
var
  D: TDate;
begin
  if DateBase = dbSolar then
    Dt := Date_SolarToGregorian(Dt);


  D := StrToDate(Dt, FormatSetting) +Step;
  Dt := DateToStr(D, FormatSetting);


  if DateBase = dbSolar then
    Dt := Date_GregorianToSolar(Dt);


  Result := Dt;
end;

----------


## hadisalahi2

الان که دقت کردم ، این کد قبلا توی یونیت شما بوده ، اما من متوجه نشدم
حالا نمیدونم چطور دو تا تابع افزودن یا کاهش تاریخ توی این یونتی هست  :متفکر: 

داش یوسف ، این تابع فقط برای اضافه کردن روز استفاده میشه؟

اگه بخوایم کم کنیم از یک تاریخ چی؟
حالا برای کاهش یا افزایش ماه چی؟

----------


## یوسف زالی

این تابع برای روزه. برای ماه فک کنم همونجا وجود داشت.
منفی بذاری می ره عقب.

----------


## hadisalahi2

این تابع منظورته دیگه؟
Function  IncMonthShamsi(DateValue:String;IncValue:Shortint)  :String;

مشکلی توی محاسبات نداره؟

----------


## یوسف زالی

من چنین تابعی ندارم!

----------


## hadisalahi2

اسم اون تابع ماه چیه عزیزم؟
تابعی به غیر از این برای ماه توی یونیت مشاهده نمی فرمایم  :لبخند گشاده!:

----------


## یوسف زالی

من برای ماه تابعی ننوشتم، اما خیلی خیلی ساده است. قسمت وسط رو بردار، اضافه و کم کن، تقسیم بر 12 اون رو هم با سال اوکی کن.
لازمه برات بنویسم؟ فک کنم دیگه خودت استاد این کارایی دیگه.

----------


## hadisalahi2

شرمنده داداش
اون وسطش رو نفهمیدم  :لبخند گشاده!: 

شما که زحمت کشیدی ، اون دوخط رو هم اضافه کن  :خجالت:

----------


## یوسف زالی

این رو الان نوشتم، تست کن بهم بگو.

function Date_MoveMonth(Dt: string; Step: integer; DateBase: TDateBase): string;
var
  years, months, days: integer;
  SYear, SMonth, SDay: integer;
  MaxValid: integer;
begin
  SYear := StrToInt(Copy(Dt, 1, 4));
  SMonth := StrToInt(Copy(Dt, 6, 2));
  SDay := StrToInt(Copy(Dt, 9, 2));


  years := Step div 12;
  months := Step mod 12;


  SYear := SYear + years;
  SMonth := SMonth + months;


  if SMonth > 12 then
    begin
    dec(SMonth, 12);
    inc(SYear);
    end;


  if SMonth < 1 then
    begin
    inc(SMonth, 12);
    dec(SYear);
    end;


  MaxValid := Date_DaysPerMonth(SYear, SMonth, DateBase);
  SDay := IfThen(SDay > MaxValid, MaxValid, SDay);


  Result := RightStr('000' + IntToStr(SYear), 4) + '/' + RightStr('0' + IntToStr(SMonth), 2) + '/' + RightStr('0' + IntToStr(SDay), 2);
end;

----------


## golbafan

سلام دوست عزیز
مواردی که زحمت کشیدید رو میخوام از دو منظر نقد کنم 
قبلش هم مجدد از زحمات شما قدر دانی میکنم

نقد من به کار شما:
1- آیا واقعا دقت 5000 ساله لازمه یا نه ؟؟ درسته از لحاظ برنامه نویسی کار جالبیه ولی آیا از لحاظ منطقی هم جالبه؟؟؟
و این مطلب که با تقویم رسمی ایران چک کردین و یکسان بوده باز هم دلیل بر دقت اون نمیشه چرا که سایت تقویم رسمی ایران هم داره از یک همچین الگوریتمی استفاده میکنه و در واقع کار شما فقط یک پیاده سازی مجدد میتونه باشه!

2- کامپوننت رایگان، اپن سورس و بسیار دقیقی به نام xcalendar وجود داره که نه تنها میلادی و شمسی رو تبدیل میکنه بلکه تقویم هجری قمری رو نیز با دو روش محاسبه و تبدیل میکنه
روش عادی و روش Astro که دقیق تر هست و با استفاده از علم ستاره شناسی کار میکنه
همچنین شامل توابع زیادی میشه که برای کار با تاریخ در دیتابیس و یا بصورت عادی میشه از اونها استفاده کرد.
این نکته دوم رو بابت این عرض کردم که خدمتتون یاد آوری کنم که لازم نیست هر چیزی رو در امضای خودمون قرار بدیم

3- اما بدترین خاصیت یونیت شما استفاده از رشته هاست و همینطور در نظر نگرفتن formatstring استاندارد!

*با تشکر فراوان


سعی میکنم مواردی رو که گفتم برات اصلاح کنم بزارم اینجا*

----------


## یوسف زالی

کار خوبی می کنید نقد می کنید. بنده با این که انتقاد رو دوست ندارم (!!) اما همیشه در موردش فکر می کنم و سعی در اصلاح مواردی که به نظرم واقعیه می کنم.

1- در مورد سورس:
مرجع تاریخ رسمی ایران تقویم رسمی ایرانه و باید با اون چک بشه. این که شما یه برنامه حسابداری می نویسی آیا پیاده سازی مجدد اون نیست؟ خب برو بخرش راحت تره که!
این نقد رو وارد نمی دونم. بنده جنبه آموزشی اون رو مد نظر دارم و نه تبلیغ، که اصلا از این موارد نه پولی در میارم و نه حاضرم در بیارم، همونطور که می بینید دیباگ رایگان هم ارائه داده می شه.
در مورد کامپوننت رایگان، اول که کار خوبی می کنید معرفی می کنید، تا دوستان و من هم ازش استفاده کنیم.
اما صرف وجود چنین کامپوننتی دلیل نمی شه کار دیگه ای انجام نشه، فکر می کنم در اوایل همین تاپیک مطرح کردم که این نمونه سورس آموزشی هست و از دل کامپوننتی که برای شرکتم نوشتم بیرون کشیدم. بنابراین ذاتا و طبیعتا جایگاهی نداره که از کامپوننت مورد معرفی شما در دل کامپوننت خودم wrap کنم.
یونیت بهترین یونیت در مارکت نیست، با اسمبلی بنویسی خیلی سریعتر هم می شه، اصراری هم بر این که بهترین سورس نوشته شده نیست.
رشته ای بودن دلایل متعدد داره و برای نیاز من و جند نفر از دوستان انجام شده. تبدیل توابع از رشته ای به استاندارد فکر نمی کنم کلا یکی دو ساعت برای کل یونیت زمان بگیره.

2- در مورد گذاشتن لینک در امضا:
این که در امضای بنده چه چیزی هست کاملا شخصی هست. موارد موجود در امضای هر شخص اگر از فیلتر قانون رد شده باشه به کسی مرتبط نیست. این از این جهت که بصورت عمومی ایراد گرفتید.
اما دلیل وجودش رو براتون می گم، مدیران سایت معمولا بیشترین افرادی هستند که بهشون ارجاع می شه، در خصوصی / در تاپیک ها / درخواست ها / گزارشات کاربران / شکایات و ...
لینکی که در امضا گذاشته شده در حقیقت مشکل خیلی از دوستان بود که چه در سایت چه بصورت تلفنی خواسته شده بود. وجود این لینک یعنی دسترسی سریع تر و بدون نیاز به جستجو برای دوستان من. اگر شما ایرادی وارد می دونید که از قوانین تخطی شده، می تونید با مدیران ارشد در میون بگذارید. اما اگر نیت طعنه زدن هست (که بعید می دونم) بنده نیازی به معرفی شدن خودم نمی بینم، مدیران ارشد دوستان مستقیم بنده هستند (بعد از مدیریت بنده) و با سایر دوستان مدیر سایر تالار ها هم دوستی و بعضا رفت و آمد هم دارم. من و شما هم اونقدر سرمون شلوغ هست که نیاز نداشته باشیم به "تو بوق کردن یک کار ساده"

3- امید خیلی زیادی دارم که از توانایی دوستان (خصوصا شما) بصورت هدفمند استفاده بشه. درگیر حاشیه شدن رو هیچ وقت دوست نداشتم.

4- یک سر به تالار های دیگه هم بزنید، چکشی برخورد کردن رو هرگز دوست نداشتم، اگر هم می بینید که زمان برای این تالار می گذارم، فقط و فقط به عشق دوستان هست و لا غیر.

5- چنانچه انتقاد یا شکایتی از کسی دارید لطفا بصورت خصوصی مطرح کنید. یا با شخص، یا با مدیر مرتبط.

پست های بی ارتباط با این مبحث پاک خواهد شد. در صورتی که قانع نشدید یا دلخوری ای دارید، لطفا با شماره بنده (در پروفایلم هست) تماس بگیرید یا با مدیران ارشد در میون بگذارید.
متشکرم.

----------


## hadisalahi2

> 2- کامپوننت رایگان، اپن سورس و بسیار دقیقی به نام xcalendar وجود داره که نه تنها میلادی و شمسی رو تبدیل میکنه بلکه تقویم هجری قمری رو نیز با دو روش محاسبه و تبدیل میکنه


با این مورد کاملا مخالفم
این کامپوننت با این که بسیار عالی و کاربردیه ، اما محاسبات تاریخش در خیلی جاها دقیق نیست
من با این کامپوننت خیلی کار کردم و ایراداتی پیدا کردم در محاسباتش که مجبور شدم برم سراغ یک یونیت دیگه

بارها هم این مطلب رو گفتم
اما یونیت یوسف جان ، تست کردم و تا الان که خدا رو شکر مشکلی در محاسبه نداشته  :لبخند گشاده!: 
البته یک ایراد در اختلاف دو تاریخ وجود داشت که رفع شد

----------


## hadisalahi2

> 4- یک سر به تالار های دیگه هم بزنید، چکشی برخورد کردن رو هرگز دوست نداشتم، اگر هم می بینید که زمان برای این تالار می گذارم، فقط و فقط به عشق دوستان هست و لا غیر.


در این مورد من هم میخواستم بارها توی یکی از پست ها این مطلب رو بگم ، اما گفتم شاید تعریف از خود باشه

من به خیلی از تالارهای  سایت مراجعه میکنم مخصوصا به تالار دات نت 
این رو به جرات میگم ،که هیچ تالاری در این سایت به اندازه تالار دلفی فعال نیست و اعضای هیچ تالاری به اندازه این تالار به همدیگه کمک نمیکنند


منم امیدوارم به جای بحث های حاشیه ای و بی خود ، تلاشمون رو برای کمک بیشتر به همدیگه بزاریم .

یا حق

----------


## golbafan

سلام خدمت دوستان عزیز
اگر از حرفام موردی رو برداشت کردید که ناپسند بوده من همینجا عذز خواهی میکنم چون *واقعا قصد جسارت نداشتم*
که از این جمله ی آخرم فکر کنم مشخص هست: "*سعی میکنم مواردی رو که گفتم برات اصلاح کنم بزارم اینجا*"
چون در کل از کلیات کارتون خوشم اومده بود اومدم اینجا پیغام گزاشتم و نظرم رو در موردش دادم وگرنه این کار رو نمیکردم!

اما دلیل نمیشه ضعف هایی رو که میبینم رو بهتون نگم تا رفعش کنید
و باز هم دلیل نمیشه در مقابل انتقاد ها زود برنجیم!!
مخصوصا که انتقاد از شخص شما نبوده بلکه از یونیت هست
*البته نقد من از یونیت شما به دلیل سومی که عرض کردم هنوز برام پابرجاست*

بازم از زحماتت تشکر میکنم

----------


## یوسف زالی

یونیت عاری از عیب نیست. بهینه ترین هم نیست. آموزشیه، و البته برای کار خاص.
زمان لازم رو برای اصلاح ندارم، طبق صلاحدید خودتون می تونید اون رو اصلاح کنید، و اگر چنین کاری کردید خوشحال می شم همینجا بگذارید.

----------


## یوسف زالی

هادی جان تست کردی؟ اگر مشکلی داشت / نداشت مطرح کن.

----------


## hadisalahi2

سلام
داش یوسف به یه مشکل برخورد کردم
اول اینکه تفاوت توابع Date_DifDate با Date_DaysBetween در چیه؟

در اختلاف دو تاریخ ، اشتباه محاسباتی هستش البته برای من
حالا شما چک کنید ببنید کجاش مشکل داره

تاریخ 1392/04/28 الی 1394/02/24  اختلافش رو برمیگردونه : 431
تاریخ 1392/03/26 الی 1393/12/06  اختلافش رو برمیگردونه : 620
تاریخ 1392/04/26 الی 1394/02/24  اختلافش رو برمیگردونه : 429

و چند تای دیگه
البته من از تابع Date_DaysBetween استفاده کردم
میشه لطفا شما چک کنی ببینی این مشکل برای شما هم هست یا نه

----------


## hadisalahi2

سلام
دو تا مطلب در مورد یونیت :

1-  تایع Date_MoveMonth رو تست کردم ردیف بود و محاسباتش صحیحه.

2- در مورد این اختلاف بین دو تاریخ ، یک نکته جالب فهمیدم و اینکه جای تاریخ ها رو توی فراخوانی تابع عوض کردم ، خروجی درست شد

----------


## golbafan

سلام
یک تغییراتی که لازمه بدید اینه که موقع محاسبه اختلاف تاریخ بیاد اونها رو به ترتیب سورت کنید تا این خطا رخ نده
منظورم اینه که یونیت رو ارتقاع بدید

----------


## hadisalahi2

> منظورم اینه که یونیت رو ارتقاع بدید


راستش رو بخواهی این یک قلم رو اصلا متوجه نشدم

----------


## khoshblagh

با سلام خدمت جناب آقای زالی
احتراما در رابطه با تبدیل تاریخ میلادی به شمسی به مشکل زیر مواجه شدم.
در برنامه مورد نظر با تابع()GetDate  اس کیو ال 2012 تاریخ سرور را بدست آورده و سپس از تابع تبدیل تاریخ میلادی به شمسی استفاده مینمایم و نتیجه را در دیتا بیس ذخیره مینمایم. بعضی وقتها این تاریخ به صورت 1300/01/01 نمایش و ثبت میشود. البته به نظر من مربوط به ساختار تاریخ میلادی میباشدکه به صورت  ماه/روز/سال تعریف شده است. میخواستم بدانم که آیا تاریخ میلادی باید جهت تبدیل به تاریخ فارسی از فرمت ماه/روز/سال باشد و یا فرمت روز/ماه/سال معتبر میباشد. توضیح بیشتر اینکه فقط بعضی وقتها این مشکل از طرف کلاینتها گزارش میشود. ضمن اینکه تاریخ 1300/01/01 در یونیت شما به عنوان تاریخ غیر معتبر معرفی شده است . متشکرم

----------


## یوسف زالی

سلام.
شما وقتی ورودی استاندارد تاریخ وارد می کنید در حقیقت دارید یک عدد وارد می کنید، اما اگر اون ورودی تبدیل به فرمت رشته ای بشه و فرمت رشته ای رو تبدیل به شمسی کنید، باید ترتیب روز ماه سال رو رعایت کنید.
در این صورت احتمال داره تنظیمات زمان کلاینت مورد نظر اشکال داشته باشه.

----------


## یوسف زالی

> یک تغییراتی که لازمه بدید اینه که موقع محاسبه اختلاف تاریخ بیاد اونها رو به ترتیب سورت کنید تا این خطا رخ نده


لازمه که هر دو حالت موجود باشه، حتی یونیت خود دلفی هم سورت نمی کنه.
نیازی به این کار نیست. این کار برعهده برنامه نویسه.

----------


## khoshblagh

> لازمه که هر دو حالت موجود باشه، حتی یونیت خود دلفی هم سورت نمی کنه.
> نیازی به این کار نیست. این کار برعهده برنامه نویسه.


شما وقتی ورودی استاندارد تاریخ وارد می کنید در حقیقت دارید یک عدد وارد می کنید، اما اگر اون ورودی تبدیل به فرمت رشته ای بشه و فرمت رشته ای رو تبدیل به شمسی کنید، باید ترتیب روز ماه سال رو رعایت کنید.
در این صورت احتمال داره تنظیمات زمان کلاینت مورد نظر اشکال داشته باشه.[/QUOTE]
با سلام
من به روش زیر اینکار را انجام میدهم. آیا اینکار درست است؟ در ضمن این کد تاریخ سرور را برمیگرداند پس احتمالا تنظیمات زمان کلاینت نباید روی آن تاثیر داشته باشد! خواهشمندم بیشتر راهنمایی بفرمائید.

   qryDateTimeServer.Close;
   qryDateTimeServer.SQL.Clear ;
   qryDateTimeServer.SQL.Add('SELECT GetDate() AS GD');
   qryDateTimeServer.Open;
   strDate:=Copy(qryDateTimeServer.FieldByName('GD').  Asstring,1,10);
   strDate:=Copy(strDate,7,4)+'/'+Copy(strDate,1,2)+'/'+Copy(strDate,4,2);
   mskTarikhSabtWahed.Text:=Date_GregorianToSolar(str  Date);
   strTime:=Copy(qryDateTimeServer.FieldByName('GD').  Asstring,12,8);
   edtSaatKarbar.Text:=strTime;

----------


## یوسف زالی

روال کار متد AsString رو عینا براتون می گذارم:

procedure TDateTimeField.GetText(var Text: string; DisplayText: Boolean);
var
  F: string;
  D: TDateTime;
begin
  if GetValue(D) then
  begin
    if DisplayText and (FDisplayFormat <> '') then
      F := FDisplayFormat
    else
      case DataType of
        ftDate: F := ShortDateFormat;
        ftTime: F := LongTimeFormat;
      end;
    DateTimeToString(Text, F, D);
  end else
    Text := '';
end;


همون طور که می بینید فقط دیتا از سرور میاد و تبدیلاتش در دلفی سمت کلاینت انجام می شه و تنظیمات سیستم روی اون موثره.

----------


## یوسف زالی

قطعه کدتون رو بگذارید تست کنم.

----------


## masoud_salimy

باتشكر
شما خودتون براي نوشتن برنامه هاي تجاريتون  از اين كدها براي تبديل تاريخ استفاده ميكنيد يا از كامپوننت خاصي استفاده ميكنيد؟
بازهم ممنون بابت پاسخ گويي و زماني كه ميگذاريد

----------


## یوسف زالی

چهار ساله که از همین استفاده می کنم

----------


## fahimi

با سلام 
با تشکر لطف آقای یوسف زالی درخصوص  ارایه تابع  تاریخ. 
در صورتیکه ورودی تابع  فرمت تاریخ سیستم  yyyy-DD-mm  نباشد  برنامه  دچار خطا می شود با توجه به اینکه  اکثریت فرمت تاریخ  سیستم  yyyy/DD/mm  می باشد.در صورت امکان تغییراتی در تابع داده می شد فرمت های مختلف تاریخ سیستم تاثیری در عملکرد آن نداشته باشد.
                                                                                                                                           با تشکر

----------


## یوسف زالی

سر فرصت تابع رو با عملیات ریاضی بازنویسی می کنم و از وابستگی رشته درش میارم.
اما برای رفع اشکال باید تنظیمات اولیه یونیت رو اعمال کنید.

----------


## menal majmoe

سلام
وقتتون بخیر
بالاخره تابع agec کو ؟؟؟ من که پیداش نکردم.محاسبه کامل سن نه فقط سال.

----------


## ATULICUS

سلام

تا دوست عزیزمون وقت خالی برا بهینه کردن و بازنویسی یونیتشون پیدا می کنند ، دوستان چه پیشنهادی میدن برا یونیت یا کامپوننت شمسی ؟!


کسی کامپوننت i18n  رو تست کرده ببینه محاسباتش درسته یا نه ؟!
یونیت persiandate رو کسی تست کرده !؟

----------


## یوسف زالی

سلام. چنین تابعی اصلا در توابع من نیست،
در خصوص بهینه سازی، دیگه برام توجیه زمانی نداره دوست گرامی.
بهینه سازی از رشته ای به عددی هم از نظر زمانی تقریبا توفیری نمی کنه، مگه این که تو حلقه های تعداد بالا درگیرش باشی.
برای کارهای نرمال همین جواب می ده، خود من روی پخش مویرگی دارم ازش استفاده می کنم.
موفق باشید.

----------

