Форум » [x]Harbour » Облачные сервисы (WebDAV, CalDAV &Co) » Ответить

Облачные сервисы (WebDAV, CalDAV &Co)

Dr. Oldwarez: После некоторого разбирательства с прогой удалось организовать импорт из ICAL-файлов и экспорт в оные. Но тут шеф захотел, чтобы был прямой контакт с CalDav через интернет. Я знаю, что на питоне такое возможно. На дельфине и даже Xojo (RealBasic) тоже - через спецбиблиотеку. Но как реализовать подключение к облачному сервису в Harbour/Minigui? Возможно ли это вообще?

Ответов - 174, стр: 1 2 3 4 5 6 7 8 9 All

Dr. Oldwarez: Петр пишет: #include "ics.ch" Я имел в виду файл заголовка ics.ch. В директории заголовочных файлов у меня его нет.

Петр: Dr. Oldwarez пишет: Я имел в виду файл заголовка ics.ch. Пост №1671

Dr. Oldwarez: Петр пишет: У вас sf_getevent для использования с IcsToArray Для IcsToArray2 sf_GetEvent() код нужно модифицировать Читайте внимательно Код в посте №1669 исправил для использования IcsToArray2 Спасибо! Всё исправил. И уже начало импортировать. Теперь только проблема отфильтровывания дубликатов.


Dr. Oldwarez: И снова здравствуйте. Всё уже вроде работает, но проблема теперь с часовыми поясами. При импорте из онлайн-календаря в локальную базу данных получается так, что все даты сходят на время по Гринвичу. А у заказчика UTC+1 зимой и UTC+2 летом. Как сделать, чтобы при импорте правильно подхватывало зимнее/летнее время? Какая есть функция для определения время летнее или зимнее? По ключу TZID и потом ниже выходит какая-то дикая абракадабра.

SergKis: Dr. Oldwarez пишет Какая есть функция для определения время летнее или зимнее? Использую такие ф-ии [pre2] *----------------------------------------------------------------------------* FUNCTION nUx2cDts( nUx, lDts ) // nUx := 1508186400 *----------------------------------------------------------------------------* LOCAL dDate, cDate, cTime DEFAULT lDts := .F. tDate := hb_datetime( 1970, 1, 1 ) + nUx / 86400 IF lDts ; RETURN tDate ENDIF cDate := DtoS( hb_TtoD( tDate ) ) cTime := hb_TtoC( tDate ) cTime := Subs( cTime, At(" ", cTime) + 1 ) cTime := StrTran( cTime, ":", "" ) cTime := StrTran( cTime, ".", "" ) RETURN ( cDate + cTime ) *----------------------------------------------------------------------------* FUNCTION Gmt2Utc( cDate, lTrans, nHour ) *----------------------------------------------------------------------------* LOCAL tDtm, tUtc, cTm1, cTm2 LOCAL dDat, dNew, cTim LOCAL nTime, cTime LOCAL lHour := .T. // "+" LOCAL lDate := Empty(cDate) STATIC s_nHour DEFAULT cDate := DtoS(Date())+StrTran(Time(), ":", "") IF ISLOGICAL(nHour) ; lHour := nHour ; nHour := Nil ELSEIF ISCHAR(nHour) ; lHour := "+" $ nHour ; nHour := Nil ENDIF dDat := StoD(left(cDate, 8)) dNew := dDat cTim := Transform(Val(subs(cDate, 9, 6)), "99:99:99") IF s_nHour == Nil .or. lDate cTm1 := cTm2 := "" tDtm := hb_DateTime() tUtc := hb_TSToUTC( tDtm ) HB_TTOD( tDtm, @cTm1, "hh:mm:ss" ) HB_TTOD( tUtc, @cTm2, "hh:mm:ss" ) s_nHour := Val(cTm1) - Val(cTm2) ENDIF DEFAULT nHour := iif( lHour, s_nHour, -(s_nHour) ) , lTrans := .T. nTime := Secs(cTim) + nHour*60*60 cTime := SecToTime(nTime + iif( nTime < 0, 24*60*60, 0 )) IF nHour < 0 ; dNew -= iif( Secs(cTime) > Secs(cTim ), 1, 0 ) ELSE ; dNew += iif( Secs(cTim ) > Secs(cTime), 1, 0 ) ENDIF cDate := DtoS( dNew ) + StrTran( cTime, ":", "" ) IF lTrans ; cDate := Transform( cDate, "@R 9999-99-99 99:99:99" ) ENDIF RETURN cDate [/pre2] Использование [pre2] oCol := :GetColumn("R_DTM") ; oCol:nAlign := DT_CENTER oCol:cPicture := "@R 9999-99-99 99:99:99" oCol:nWidth := oCol:ToWidth(subs(oCol:cPicture, 2)) oCol:bDecode := {|cd| Gmt2Utc(cd, .F.) } oCol:cHeading := StrTran(ot:cDtms, "\", CRLF) ... по кнопке OK! для GETBOX-ов периода даты и периода времени :Event(10, {|ow,ky,cn| LOCAL o := Sys.Cargo, ot := Sys.Cargo:oBaseText LOCAL oObj := ow:Cargo:oObject, aTmp, cTmp, cDt1, cDt2, cFil, cObj LOCAL aObj := {}, cGm1 LOCAL aNam := {}, cGm2 LOCAL cNam := This.Events.Value LOCAL dDt1 := This.PeriodFrom.Value LOCAL dDt2 := This.PeriodTo.Value LOCAL cTm1 := This.TimesFrom.Value LOCAL cTm2 := This.TimesTo.Value ... cTm1 := left(trim(cTm1)+repl("0", 6), 6) cTm2 := left(trim(cTm2)+repl("0", 6), 6) cDt1 := hb_DtoC(dDt1, "YYYYMMDD")+cTm1 cDt2 := hb_DtoC(dDt2, "YYYYMMDD")+cTm2 cGm1 := Gmt2Utc(cDt1, .F., .F.) cGm2 := Gmt2Utc(cDt2, .F., .F.) ... [/pre2]

Dr. Oldwarez: SergKis пишет: *----------------------------------------------------------------------------* FUNCTION nUx2cDts( nUx, lDts ) // nUx := 1508186400 *----------------------------------------------------------------------------* LOCAL dDate, cDate, cTime DEFAULT lDts := .F. tDate := hb_datetime( 1970, 1, 1 ) + nUx / 86400 IF lDts ; RETURN tDate ENDIF cDate := DtoS( hb_TtoD( tDate ) ) cTime := hb_TtoC( tDate ) cTime := Subs( cTime, At(" ", cTime) + 1 ) cTime := StrTran( cTime, ":", "" ) cTime := StrTran( cTime, ".", "" ) RETURN ( cDate + cTime ) lDts - Date Shift, я так понимаю. nUx - это какое-то астрономическое число, но что оно означает? Тут идёт приплюсовка часа к времени, но как определить точно, это зимнее (от последнего воскресенья октября до последнего воскресенья марта) или летнее время?

SergKis: Dr. Oldwarez пишет nUx - это какое-то астрономическое число, но что оно означает? см. http://clipper.borda.ru/?1-3-0-00000631-000-0-0-1618297675 возможно эта ф-я не нужна. но как определить точно, это зимнее (от последнего воскресенья октября до последнего воскресенья марта) или летнее время? ф-я Gmt2Utc(...) определяет разницу gmt и местного времени. Определяйте сами запуская Gmt2Utc(NIL) хоть каждый час разницу зимнего или летнего времени. В показанном варианте ф-ии дата timestamp (gmt) строковая без разделителей, т.к. именно такая хранится в базе dbf для упрощения работы с индексами (данные получены из FireBird ф-ей nUx2cDts( nUx )). За месяц ~2 500 000 записей, базы годовые.

Dr. Oldwarez: SergKis пишет: *----------------------------------------------------------------------------* FUNCTION Gmt2Utc( cDate, lTrans, nHour ) *----------------------------------------------------------------------------* Итак, попытаюсь расшифровать: cDate - входная дата и время по Гринвичу lTrans - указание формата вывода ГГГГ-ММ-ДД ЧЧ:ММ:СС 2021-07-26 12:30:00 Что здесь делает статический s_nhour? А параметр nHour - это заданный сдвиг относительно Гринвича?

SergKis: hb_TSToUTC( [<tLocalTime>] ) ➜ tUtcTime -> converts a local time tTIMESTAMP to UTC time. hb_DateTime() -> local time tTIMESTAMP cDate - Utc время из базы тип char, значение без миллисекунд, т.е. '20201203102045' s_nHour - разница в часах локального времени и Utc времени, т.е. для нас: 3 - часа для летнего, 2 - для зимнего времени вычисляем при входе в программу и можно переустановить s_nHour в каком то режиме (по таймеру, каждый час) используется дальше как константа для отображения данных базы в локальном времени (в TsBrowse) и после GETBOX запросов периода дат, времени (локальное время задается), приводим ко времени Utc для работы с базой (SET SCOPE ..., SET FILTER ... и т.д.) lTrans используется для TsBrowse отображения в колонках или Label, если не задаем Picture Пример [pre2] @ y, x LABEL Period VALUE ot:cPer+":" WIDTH oDlu:W1 HEIGHT h FONT "FormNorm" BACKCOLOR aBClr x += This.Period.Width @ y, x LABEL PerFrom VALUE ot:cPers WIDTH oDlu:W1 HEIGHT h FONT "FormNorm" BACKCOLOR aBClr CENTERALIGN x += This.PerFrom.Width + 2 @ y, x GETBOX PeriodFrom OBJ oGet WIDTH oDlu:D3 HEIGHT h VALUE CtoD("") ; ACTION {|| _wPost(5, , This.Name) } IMAGE "view" PICTURE Nil ; BUTTONWIDTH h FONT "FormNorm" BACKCOLOR BClr ; ON INIT {|og| og:lOnGotFocusSelect := .T. } oGet:OnF5 := {|og| _wPost(5, , og:cControlName) } // VK_F5 x += This.PeriodFrom.Width + 2 @ y, x LABEL PerTo VALUE ot:cPerp WIDTH oDlu:W1 HEIGHT h FONT "FormNorm" BACKCOLOR aBClr CENTERALIGN x += This.PerTo.Width + 2 @ y, x GETBOX PeriodTo OBJ oGet WIDTH oDlu:D3 HEIGHT h VALUE CtoD("") ; ACTION {|| _wPost(6, , This.Name) } IMAGE "view" PICTURE Nil ; BUTTONWIDTH h FONT "FormNorm" BACKCOLOR BClr ; ON INIT {|og| og:lOnGotFocusSelect := .T. } oGet:OnF5 := {|og| _wPost(6, , og:cControlName) } // VK_F5 y := This.Period.Row + This.Period.Height + nGh x := This.Period.Col @ y, x LABEL Times VALUE ot:cTime+":" WIDTH oDlu:W1 HEIGHT h FONT "FormNorm" BACKCOLOR aBClr x += This.Times.Width @ y, x LABEL TimeFrom VALUE ot:cPers WIDTH oDlu:W1 HEIGHT h FONT "FormNorm" BACKCOLOR aBClr CENTERALIGN x += This.TimeFrom.Width + 2 @ y, x GETBOX TimesFrom OBJ oGet WIDTH oDlu:D3 HEIGHT h VALUE space(6) ; PICTURE "@R 99:99:99" VALID {|og,hw2| bValid(og, hw2) } ; BUTTONWIDTH h FONT "FormNorm" BACKCOLOR BClr ; ON INIT {|og| og:lOnGotFocusSelect := .T. } x += This.TimesFrom.Width + 2 @ y, x LABEL TimeTo VALUE ot:cPerp WIDTH oDlu:W1 HEIGHT h FONT "FormNorm" BACKCOLOR aBClr CENTERALIGN x += This.TimeTo.Width + 2 @ y, x GETBOX TimesTo OBJ oGet WIDTH oDlu:D3 HEIGHT h VALUE space(6) ; PICTURE "@R 99:99:99" VALID {|og,hw2| bValid(og, hw2) } ; BUTTONWIDTH h FONT "FormNorm" BACKCOLOR BClr ; ON INIT {|og| og:lOnGotFocusSelect := .T. } ... :Event(10, {|ow,ky,cn| // OK button LOCAL o := Sys.Cargo, ot := Sys.Cargo:oBaseText LOCAL oObj := ow:Cargo:oObject, aTmp, cTmp, cDt1, cDt2, cFil, cObj LOCAL aObj := {}, cGm1 LOCAL aNam := {}, cGm2 LOCAL cNam := This.Events.Value LOCAL dDt1 := This.PeriodFrom.Value LOCAL dDt2 := This.PeriodTo.Value LOCAL cTm1 := This.TimesFrom.Value LOCAL cTm2 := This.TimesTo.Value LOCAL oBuf := oKeyData() oBuf:cOwn := "" oBuf:cObj := "" oBuf:cPer := "" oBuf:cTim := "" oBuf:lRowId := This.RowID.Value FOR EACH aTmp IN oObj:GetAll() ; AAdd(aObj, aTmp[1]) NEXT IF Empty(aObj) cObj := This.ObjNum.Value IF Empty(cObj) MsgStop("Empty objects !", "ERROR") This.ObjNum.SetFocus DO EVENTS RETURN Nil ELSE aObj := { Tr0(cObj, 12) } ENDIF ENDIF DO EVENTS IF Empty(dDt1) MsgStop("Period: Date error or empty date from !", "ERROR") This.PeriodFrom.SetFocus DO EVENTS RETURN Nil ENDIF IF Empty(dDt2) MsgStop("Period: Date error or empty date to !", "ERROR") This.PeriodTo.SetFocus DO EVENTS RETURN Nil ENDIF IF dDt1 > dDt2 MsgStop("Period: Date from > Date to !", "ERROR") This.PeriodFrom.SetFocus DO EVENTS RETURN Nil ENDIF cTm1 := left(trim(cTm1)+repl("0", 6), 6) cTm2 := left(trim(cTm2)+repl("0", 6), 6) cDt1 := hb_DtoC(dDt1, "YYYYMMDD")+cTm1 cDt2 := hb_DtoC(dDt2, "YYYYMMDD")+cTm2 lEmpty := Empty(Val(cTm1)) .and. Empty(Val(cTm2)) IF lEmpty cGm1 := Gmt2Utc(cDt1 , .F., .F.) cDt2 := hb_DtoC(dDt2+1, "YYYYMMDD")+cTm2 cGm2 := Gmt2Utc(cDt2 , .F., .F.) ELSE cGm1 := Gmt2Utc(cDt1, .F., .F.) cGm2 := Gmt2Utc(cDt2, .F., .F.) ENDIF cNam := trim(cNam) IF !Empty(cNam) FOR EACH cTmp IN hb_ATokens(cNam, ";") IF !Empty(cTmp) ; AAdd( aNam, upper(alltrim(cTmp)) ) ENDIF NEXT ENDIF IF Len(aObj) > 1 ; aObj := ASort(aObj) ENDIF oBuf:aObj := aClone(aObj) oBuf:cOwn := "" oBuf:cObj := "" oBuf:cPer := hb_DtoC(dDt1, "DD.MM.YYYY")+"."+" - "+hb_DtoC(dDt2, "DD.MM.YYYY")+"." IF !Empty(Val(cTm1)) .and. !Empty(Val(cTm2)) oBuf:cTim := Transform(cTm1, "@R 99:99:99")+" - "+Transform(cTm2, "@R 99:99:99") ENDIF oMain:StatusBar:Say(ot:cWait, 1) ; DO EVENTS cFil := Select_God( cGm1, cGm2, aObj, aNam, lEmpty ) oMain:StatusBar:Say("", 1) ; DO EVENTS IF !Empty(cFil) .and. hb_FileExists(cFil+".dbf") wSelectEvent(cFil, oBuf) ENDIF RETURN Nil }) ... [/pre2]

Dr. Oldwarez: SergKis пишет: s_nHour - разница в часах локального времени и Utc времени, т.е. для нас: 3 - часа для летнего, 2 - для зимнего времени вычисляем при входе в программу А как именно его вычисляют? Или всё же прописывают в файле INI?

SergKis: Dr. Oldwarez пишет как именно его вычисляют? В тексте ф-ии[pre2] IF s_nHour == Nil .or. lDate cTm1 := cTm2 := "" tDtm := hb_DateTime() tUtc := hb_TSToUTC( tDtm ) HB_TTOD( tDtm, @cTm1, "hh:mm:ss" ) HB_TTOD( tUtc, @cTm2, "hh:mm:ss" ) s_nHour := Val(cTm1) - Val(cTm2) ENDIF [/pre2]

Dr. Oldwarez: Итак, у меня всё, вроде работает, но вот у шефа с той же прогой файл listall_ics.xml, который должен использоваться для считывания данных из онлайн-календаря выдаёт такую вот хрень. Я так понимаю, это шеф неправильно ввёл свои имя пользователя и пароль. [pre2]<?xml version="1.0" encoding="utf-8"?> <d:error xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns"> <s:exception>Sabre\DAV\Exception\NotAuthenticated</s:exception> <s:message>Username or password does not match</s:message> <s:sabredav-version>1.8.12</s:sabredav-version> </d:error>[/pre2]

Петр: Dr. Oldwarez пишет: Я так понимаю, это шеф неправильно ввёл свои имя пользователя и пароль. Да

Dr. Oldwarez: И снова здравствуйте! Там у шефа был пароль с запретным символом, попросил заменить, потом в условии фильтра немного порылся. Вроде, работает, но только на стационарных компах. Если событие онлайн-календаря вводят с телефона - жутко коверкает даты и время, кроме конечной даты. Стартовая дата всегда - 27 октября 1996 год. Время коверкает в обеих случаях. В чём разница между событием, введённым с компа и таковым с мобилки? [pre2] IF aCalStr[nBuf]="DTSTART" cDateTime:=SUBSTR(aCalStr[nBuf],AT(":",aCalStr[nBuf])+1) dStartDate:=STOD(LEFT(cDateTime,8)) cStartTime:=STRZERO(VAL(SUBSTR(cDateTime,10,2))+nTimeZone,2)+":"+SUBSTR(cDateTime,12,2) [/pre2] Тут, как видите, в качестве разделителя используется двоеточие. Возможно, в мобильниках какой-то другой символ, но как это влияет на календарь? Upd: с мобильника то же двоеточие, но даты искажаются до 1916, 1917 года. Upd2: в случае, если событие создано на андроидном мобильнике, но потом изменено и сохранено на компьютере - всё в порядке. Дата передаётся правильно, даже если меняют только текст.



полная версия страницы