Date de début et date de fin mutuellement restrictives-heures utilisant P: Calendrier (pas de validation)

nous avons une exigence de présenter deux p:calendrier composants à l'utilisateur, représentant une date de début et de fin chacun. Les deux datetimes ont des dates, des heures et des minutes. PrimeFaces a parfait mindate , maxdate , minHour , maxHour , minMinute , et minMinute attributs disponibles.

L'exigence est maintenant:

il est impossible de définir la date de début à quoi que ce soit de plus grand ou égal à la date de fin. Il est impossible de définir la fin datetime à quoi que ce soit inférieure ou égale à la fin datetime.

l'équation suivante devrait être vraie:

begin datetime < end datetime

maintenant nous avons essayé le JSF suivant:

<p:calendar id="begin-date"
            value="#{debugManager.selectedBeginDate}"
            mindate="#{debugManager.minBeginDate}"
            maxdate="#{debugManager.maxBeginDate}"
            maxHour="#{debugManager.maxBeginHour}"
            maxMinute="#{debugManager.maxBeginMinute}"
            pattern="yyyy-MM-dd HH:mm"
            showButtonPanel="true"
            readonlyInput="true"
            navigator="true"
            showOn="button"
            required="true">
    <p:ajax event="dateSelect" update="end-date" />
</p:calendar>

<p:calendar id="end-date"
            value="#{debugManager.selectedEndDate}"
            mindate="#{debugManager.minEndDate}"
            minHour="#{debugManager.minEndHour}"
            minMinute="#{debugManager.minEndMinute}"
            pattern="yyyy-MM-dd HH:mm"
            showButtonPanel="true"
            readonlyInput="true"
            navigator="true"
            showOn="button">
    <p:ajax event="dateSelect" update="begin-date" />
</p:calendar>

voici un exemple de méthode min/max (mindate of end-date):

public Date getMinEndDate()
{
    return this.getSelectedBeginDate();
}

comme vous pouvez le voir, la date de fin minimale est la date de début actuellement sélectionnée par AJAX. Fixer correctement une date de fin ne permet pas de définir la date de début après la date de fin.

Les problèmes commencent lorsque impliquant le temps dans l'équation...

puisque l'interface de P: calendar a des méthodes séparées, le haricot doit fournir la logique:

public int getMinEndHour()
{
    Date selectedBeginDate = this.getSelectedBeginDate();
    Date selectedEndDate = this.getSelectedEndDate();

    if ( selectedBeginDate != null && DateUtil.isSameDay( selectedBeginDate, selectedEndDate ) )
    {
        return DateUtil.getHourOf( selectedBeginDate );
    }

    return ComplianceConstants.DEFAULT_COMPLIANCE_CASE_MIN_END_HOUR;
}

cela dit fondamentalement seulement si une date de début a été fixée et si les dates de début et de fin sont actuellement les mêmes, restreindre l'Heure de fin sélectionnable ( minHour de date de fin) à l'Heure de début.

opérations:

Set the begin datetime to 2013-04-20 12:34 (legit)
Set the end   datetime to 2013-04-22 00:00 (legit)

maintenant, l'Heure de la date de fin se situe à 00: 00 et le choix d'une date de calendrier 2013-04-20 devrait être autorisé aussi longtemps que l'Heure de fin est en quelque sorte ajustée à au moins 12:35.

le P: calendrier composante cependant ne peut pas savoir cela et maintenant

sets the end datetime to 2013-04-20 00:00 (legit, but false)

...

Le problème maintenant est que lorsque l'utilisateur appuie sur une certaine nouvelle date dans le calendrier, les attributs mindate/maxdate ne peuvent pas restreindre l'utilisateur à frapper la même date que la date de début. Si la date de fin heure se trouve maintenant avant la même date de début il n'y a rien que nous pouvons faire à ce sujet (ce qui est mal).

le problème de suivi est maintenant que l'utilisateur est en mesure de fermer le calendrier et il suffit d'appuyer sur le bouton Soumettre pour insérer de fausses données dans le DB. Bien sûr, un validateur pourrait / devrait être lancé, mais nous devons d'une manière ou d'une autre réaliser ceci sans un validateur .

ce que nous essayions ensuite était de patcher les setSelectedBeginDate( Date selectedBeginDate ) et setSelectedEndDate( Date selectedEndDate ) méthodes pour ajuster l'ensemble java.util.Date portions de temps si les dates étaient le même jour. Quelque chose comme ceci:

public void adjustSelectedEndDate()
{
    if ( this.selectedEndDate != null )
    {
        this.log.infov( "adjustSelectedEndDate: b-hour = {0}, e-hour = {1}", DateUtil.getHourOf( this.selectedBeginDate ), DateUtil.getHourOf( this.selectedEndDate ) );

        if ( DateUtil.isSameDay( this.selectedBeginDate, this.selectedEndDate ) &&
            ( DateUtil.getHourOf( this.selectedEndDate ) < DateUtil.getHourOf( this.selectedBeginDate ) ) ||
              DateUtil.getHourOf( this.selectedEndDate ) == DateUtil.getHourOf( this.selectedBeginDate ) && DateUtil.getMinuteOf( this.selectedEndDate ) <= DateUtil.getMinuteOf( this.selectedBeginDate ) )
        {
            this.log.info( "Adjusting selected end date!" );

            this.selectedEndDate = DateUtil.addOneMinuteTo( DateUtil.copyTime( this.selectedBeginDate, this.selectedEndDate ) );
        }
    }
}

cela nous a demandé d'ajouter @this à l'attribut update de chaque p:calendar de sorte que les getters respectifs ( getSelectedBeginDate() et getSelectedEndDate + les limiteurs min / max) seront appelés pendant la mise à jour.

placer un @this sur la mise à jour confond cependant les composants P:calendar, ce qui rend les curseurs de temps slidable qu'une seule fois. Les événements slider suivants sont tout simplement ignorés, se comportant cassés.

Q

  • comment abordez-vous généralement la résolution de ce problème?
  • est d'utiliser p:remoteCommand la façon d'atteindre ce que nous voulons?

Optionnel Q :

  • pourquoi le PrimeFaces P:calendar n'a-t-il pas été implémenté pour fournir un seul minDateTime et maxDateTime, ce qui pourrait potentiellement résoudre les problèmes actuels?

je parie que ce scénario que j'ai décrit a déjà été résolu avant. J'apprécierais beaucoup si vous pouviez décrire l'approche que vous avez réussi à résoudre ce (ou même partager un en partie solution).

40
demandé sur Kawu 2013-04-23 10:35:52

1 réponses

préface:

Je ne travaille pas avec JSF, mais il y a quelques choses qui pourraient vous ramener là où vous voulez être:

A) Lorsque fonctionne avec seulement la partie date d'une dateTime dans un calendrier standard , envisager d'utiliser:

someCalendar.set(Calendar.MILLISECOND, 0)

B) envisager d'utiliser Joda-time , comme il semble fréquemment recommandé ( ici , ici , et beaucoup d'autres endroits ) sur la bibliothèque standard pour l'exactitude, la performance, et la facilité d'utilisation dans de nombreuses situations.

c) assurez-vous que votre bean scope survit à chaque appel ajax (pas de redirection, seulement l'envoi de post-back standard, etc) et chaque gestionnaire d'événements obtient le contexte des visages (par ex. FacesContext facesContext = FacesContext.getCurrentInstance(); )

d) mindate et comme il n'y a pas de travail comme vous vous attendez , et je n'attends pas que le comportement automatique peut être aussi facilement intervenu.

quand ces options ne sont pas disponibles, et vous devez le faire vous-même avec ce que vous avez:

Philisophique / UX: La première chose que je ferais est de supprimer l'attente de l'arrangement ou la perspective de la paire de dates. Ne traitez pas la paire comme un vecteur qui expose ou attend une direction sur la timeline.

  • en d'autres termes, une date start ou from est-elle toujours inférieure ou antérieure à une date end ou to ? Non, comme on peut le voir pour une interrogation de données historiques, ou pour appliquer des corrections à des événements qui n'ont pas encore eu lieu ou qui ont déjà eu lieu?

    Cette connotation peut facilement confondre un utilisateur de savoir si ils vont 'à' ou 'avant de' (et peut facilement confondez-vous). Au lieu de cela je traiterais une paire de dates avec une période de temps entre eux comme juste et simplement que a pair of dates ou un range ou un period qui déclare un intervalle, et infer leur position relative sur la ligne de temps en fonction des valeurs choisies en conséquence. De cette façon, vous pouvez honorer les exigences inhérentes que les dates ne jamais être égaux, et la gauche est toujours vers la gauche, la droite, toujours à droite.

nous ne pouvons pas inférer ce que "commencer" ou "partir" signifie, Mais nous pouvons inférer un certain sens et une relation relative: une droite, une gauche, et un entre sur une ligne chronologique. Note: toujours résoudre les dates à UTC avant de faire un calcul ou une comparaison.

long oneDateValue = oneDate.toUtc().toMilliseconds();
long anotherDateValue = anotherDate.toUtc().toMilliseconds();

long right = max (oneDateValue, anotherDateValue);
long left = min (oneDateValue, anotherDateValue);

L'Évaluation De La Précision: La deuxième chose que je regarderais en travaillant avec une gamme de dates dans n'importe quelle langue est similaire à la façon dont vous pourraient traiter avec des nombres à virgule flottante. Pour les comparaisons, ne comparez pas pour l'égalité, mais comparez plutôt le delta à un "niveau d'erreur acceptable". En d'autres termes, la demande ne concerne en réalité qu'un certain degré de précision, alors assurez-vous que seule cette précision est saisie et prise en compte:

const int dateTimeResolutionInMs = 86400000; // milliseconds per day

public bool areEssentiallySame(long left, long right) {

   // the difference between right and left is less than our precision 
   // requires, thus dates are effectively the same
   return (right - left < dateTimeResolutionInMs);
}

Le Fait De Contraindre Une Précision: Troisièmement, comment résoudrons-nous la différence de valeurs, même si elle se situe dans les limites de la résolution? (Sur demande a été donné plus de précision qu'il peut traiter ou attendre ou les besoins).

long diff = value % dateTimeResolutionInMs;

  1. tronqué: return value - diff;

  2. la plus proche (W / biais): return value + (diff < dateTimeResolutionInMs/ 2) ? -1 * diff : dateTimeResolutionInMs - diff;

  3. autres: il y a beaucoup d'autres stratégies pour rétrécir ou étendre une valeur à une résolution ou une précision préférée

Addendum: En ce qui concerne les appels post-backs/Ajax pour retourner une vue avec les valeurs que vous attendez pour les événements déclenchés par un élément calendar , vous pouvez séparer cette préoccupation à une nouvelle question si la note dans la préface ne vous a pas mené nulle part, et vous savez avec certitude que votre haricot est correctement enregistré et reconnu. vous pouvez avoir des problèmes spécifiques à la version de votre navigateur contribuer au comportement indésirable, et comme toute autre chose, Il ya des problèmes, à la fois connus et inconnus.

1
répondu JustinC 2017-05-23 12:26:10