Do nového roku jako lepší programátoři? Znovu otevíráme večerní školu programování. Nette framework, návrhové vzory, testování nebo vůbec poprvé kurzy ASP.NET dostupné odkudkoli v republice.

Diskuze: ASP .Net - časová pásma

C# .NET .NET (C# a Visual Basic) ASP .Net - časová pásma American English version English version

Avatar
Honza
Člen
Avatar
Honza:

Ahoj, na své webové stránce (ASP .NET WebForm C#) chci přidat možnost diskuze pod příspěvky. Teď jsem ale narazil na problém jak správně zobrazovat čas vložení příspěvku tak, aby se diskutujícím správně zobrazila posloupnost přidaných příspěvků bez ohledu na jejich časové pásmo. Teď to mám nastaveno tak, že do databáze se čas ukládá jako UTC ale netuším jak ho pak správně zobrazit. Přepokládám, že pokud použiju funkci datatime ToLocalTime() tak se to převede na lokální čas serveru, nikoli uživatele.

Jak se toto v praxi řeší? Napadlo mě prostě čas zobrazovat vždy a všude v UTC, ale nevím jestli to je to pravé ořechové? A je vůbec nějaká technika jak zjistit časové pásmo uživatele?
Jde mi hlavně o směr jakým se vydat, abych si pak nenaběhl.

Díky :)

Odpovědět 24.8.2015 12:00
Snadnou cestou se daleko nedostanete, je tam velká tlačenice...
Avatar
Jan Vargovský
Redaktor
Avatar
Odpovídá na Honza
Jan Vargovský:

Ahoj,

s krásou timezón jsem bojoval pár týdnů z5. Ukládání do databáze UTC čas je rozhodně výhoda. Nicméně ukazovat uživateli UTC už je blbost. Si vezmi, že bych byl někde s UTC+10, odeslal koment a najednou viděl, že jsem odeslal koment v 03:15 místo 13:15 :D Předpokládám, že časy už renderuješ přímo do HTML, takže u klienta se ti nic nemění. Já řešil právě problém s tím, co mám odeslat na server, pak do toho srát ještě DST (daylight saving time - letní/zimní čas, jak to vůbec v JS detekovat? apod.). Tvé řešení může být jednoduché. Jednoduše při requestu na příspěvky ještě odešli offset vůči UTC a pak už to jen zkonvertuj. Popřípadě si to ajaxově odešli při loadu a pak s tím pracuj... Záleží na kontextu jakým píšeš tu appku, my načítáme všechen hlavní content skrz ajax, takže už máme na serveru takové info jako server offset, client offset a další info. Kdyžtak mi řekni jaký máš kontext a můžu ti poradit více specifičtěji.

 
Nahoru Odpovědět 24.8.2015 14:31
Avatar
Honza
Člen
Avatar
Odpovídá na Jan Vargovský
Honza:

Ahoj,

díky za comment. Můj hlavní problém je že se mi zatím nepodařilo zjistit jak získat časovou zónu (offset oproti UTC) od uživatele. Pokud budu mít ten offset tak se s tím už nějak poperu. De facto jsou podle mě možnosti dvě, buď si ten offset uložit do databáze k danému času a nebo ho použít až po načtení dat do stránky a zobrazované časy posunout o ten offset. Načítání dat mám řešeno pomocí vlastní třídy která se stará o získání dat z databáze a já je pak vkládám do stránky (datumu vkládám jako text do asp labelu), takže si s tím před zobrazením můžu dělat co chci a libovolně to upravovat.

Nahoru Odpovědět 24.8.2015 14:56
Snadnou cestou se daleko nedostanete, je tam velká tlačenice...
Avatar
Honza
Člen
Avatar
Odpovídá na Honza
Honza:

Beru zpět, ukládat to do db je blbost, musím to ukládat jako UTC a offset řešit až při requestu ;)

Nahoru Odpovědět 24.8.2015 15:05
Snadnou cestou se daleko nedostanete, je tam velká tlačenice...
Avatar
patrik.valkovic
Šéfredaktor
Avatar
Nahoru Odpovědět 24.8.2015 15:32
Nikdy neumíme dost na to, abychom se nemohli něco nového naučit.
Avatar
Jan Vargovský
Redaktor
Avatar
Odpovídá na Honza
Jan Vargovský:

Načítej si data ajaxově, pak jen načteš stránku a při requestu na commenty k tomu postneš i svůj offset.

Date.prototype.getClientTimeZoneOffset = function () {
    return (this.getTimezoneOffset() / -60);
}

Ale bacha, vrací to i včetně DST.

 
Nahoru Odpovědět 24.8.2015 15:38
Avatar
Honza
Člen
Avatar
Odpovídá na Jan Vargovský
Honza:

Díky, konečně jsem se k tomu dostal a předělávám to aby se to načítalo ajaxově. Jen jsem pořád nějak nepochopil jak zjistit tu časovou zónu. Ta funkce kterou voláš a jejíž výsledek vracíš:

return (this.getTimezoneOffset() / -60);

voláš konkrétně kde?

Nahoru Odpovědět 27.8.2015 15:11
Snadnou cestou se daleko nedostanete, je tam velká tlačenice...
Avatar
Jan Vargovský
Redaktor
Avatar
Odpovídá na Honza
Jan Vargovský:

Když posilas request. Jak se dostanu domu tak se trosku rozepisu.

Editováno 27.8.2015 16:51
 
Nahoru Odpovědět 27.8.2015 16:51
Avatar
Jan Vargovský
Redaktor
Avatar
Odpovídá na Honza
Jan Vargovský:

Sorry, zapomněl jsem.

Dejme tomu, že tohle jsou modely:

public class TempViewModel
{
    public string Title { get; set; }
}

public class MessagesModel
{
    public IList<MessageModel> Messages { get; set; }
}

public class MessageModel
{
    public string Text { get; set; }
    public DateTime DateCreated { get; set; }
}

Pak máš nějaký kontroller (u mě HomeController):

public ActionResult TempView()
{
    var model = new TempViewModel();
    model.Title = "some title";
    return View(model);
}

public string RenderPartialView(string viewName, object model)
{
    if (string.IsNullOrEmpty(viewName))
        viewName = ControllerContext.RouteData
            .GetRequiredString("action");

    ViewData.Model = model;
    using (var sw = new StringWriter())
    {
        ViewEngineResult viewResult = ViewEngines.Engines
            .FindPartialView(ControllerContext, viewName);
        var viewContext = new ViewContext(ControllerContext,
            viewResult.View, ViewData, TempData, sw);
        viewResult.View.Render(viewContext, sw);

        return sw.GetStringBuilder().ToString();
    }
}

public JsonResult GetMessages(int timezoneOffset = 0)
{
    var model = new MessagesModel() { Messages = new List<MessageModel>() };
    for (int i = 0; i < 10; i++)
        model.Messages.Add(new MessageModel { Text = $"nejaky text {i}", DateCreated = DateTime.UtcNow.AddHours(i + timezoneOffset) });


    return Json(new
    {
        result = true,
        view = RenderPartialView("MessageList", model),
    });
}

Btw, tu RenderPartial metodu jsem nepsal, ani jsem to nezkoumal, jen vzal první co fungovalo.

Pak mám nějaké TemView (včetně JS):

@model WebApplicationMVC.Models.TempViewModel

<div class="panel panel-default">
    <div class="panel-heading">
        <h1 class="panel-title">@Model.Title</h1>
    </div>
    <div id="messagesContainer">

    </div>
</div>

<script>
    Date.prototype.getClientTimeZoneOffset = function () {
        return (this.getTimezoneOffset() / -60);
    }

    $(document).ready(function () {
        $.ajax({
            type: "POST",
            url: "GetMessages",
            data: { timezoneOffset: new Date().getClientTimeZoneOffset() },
            success: function (data, status) {
                if (data.result) {
                    $("#messagesContainer").html(data.view);
                }
            },
            error: function errorFunc() {
                console.log("error");
            }
        });
    });
</script>

A nakonec MessageList view, které mi renderuje ty zprávy:

@model WebApplicationMVC.Models.MessagesModel

@if (Model != null && Model.Messages.Any())
{
    foreach (var message in Model.Messages)
    {
        <div class="message">
            <span>@message.DateCreated + @message.Text</span>
        </div>
    }
}

Když pak pustíš server s nějakým timezone offsetem (momentálně UTC+2), tak bys měl dostat ten první čas jako ten, který máš právě na PC. Pak když ho změníš a refreshneš stránku, tak bys ho měl vidět pořád překonvertovaný jako ten tvůj.

 
Nahoru Odpovědět 27.8.2015 22:33
Avatar
Mediel
Redaktor
Avatar
Odpovídá na Honza
Mediel:

Lze si v Global.asax nastavit, že veškerý čas, co opustí server je UTC a pak už by si to měl JS přebrat sám...

Nahoru Odpovědět 28.8.2015 2:31
Nechci vám ukazovat, jak dobrý jsem já ... Chci vám ukázat, jak dobrý můžete být vy ... Když uvěříte ... V sami sebe...
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 11 zpráv z 11.