web-dev-qa-db-fra.com

Utilisation de GregorianCalendar avec SimpleDateFormat

Donc, j'ai creusé mon cerveau au cours de cet exercice (qui devrait être) simple pour que le programme transforme une chaîne de date en un objet GregorianCalendar, le formate et le renvoie à nouveau sous forme de chaîne une fois terminé.

Il s'agit de la dernière partie d'un programme qui prend un morceau de texte d'un fichier, le décompose en enregistrements individuels, puis décompose les enregistrements en éléments de données individuels et les affecte à un objet personne.

J'ai vérifié le code à plusieurs endroits et le code fait exactement ce qu'il est censé faire jusqu'à ce que j'appelle la fonction de formatage, qui lance un IllegalArgumentException. L'objet GergorianCalendar se voit attribuer les valeurs qui lui sont supposées être attribuées (bien que l'impression soit, encore une fois, une toute autre histoire comme vu ci-dessous…), mais le format n'acceptera pas l'objet pour le formatage.

Malheureusement, l'instructeur n'était pas trop sûr de la façon d'utiliser les GregorianCalendar et SimpleDateFormat (pourtant nous a chargé de travailler avec eux) et a dit: "Juste Google it ..." J'ai essayé, et rien J'ai trouvé que cela avait aidé.

Le code que j'ai jusqu'à présent est:

public class DateUtil {

    public static GregorianCalendar convertFromDMY(String dd_mm_yy) throws ParseException{

        // this actually works, got rid of the original code idea
        String[] splitDate = dd_mm_yy.split("-");
        int days = Integer.parseInt(splitDate[0]);
        int month = Integer.parseInt(splitDate[1]);
        int year = Integer.parseInt(splitDate[2]);

        // Dates are going in right, checked in print statement,
        // but the object is not getting formatted…
        GregorianCalendar dateConverted = new GregorianCalendar(year, month, days);
        format(dateConverted);
        return dateConverted;
    }

    public static String format(GregorianCalendar date){

        SimpleDateFormat fmt = new SimpleDateFormat("dd-MMM-yyyy");
        String dateFormatted = fmt.format(date);
        return dateFormatted;
    }
}

L'erreur que j'obtiens est:

 Exception dans le thread "principal" Java.lang.IllegalArgumentException: impossible de formater l'objet donné en tant que date 
 
 À Java.text.DateFormat.format (DateFormat.Java:281) 
 sur Java.text.Format.format (Format.Java:140) 
 sur lab2.DateUtil.format (DateUtil.Java:26) 
 sur lab2.DateUtil.convertFromDMY (. DateUtil.Java:19)
 À lab2.Lab2.createStudent (Lab2.Java:75) 
 À lab2.Lab2.main (Lab2.Java:34) 

Et autre chose, est-ce que j'utilise même le droit GregorianCalendar ?? Lorsque j'imprime la valeur de cet objet (devrait obtenir une date, non?) J'obtiens ceci:

Java.util.GregorianCalendar [time = ?, areFieldsSet = false, areAllFieldsSet = false, lenient = true, zone = Sun.util.calendar.ZoneInfo [id = "America/Vancouver", offset = -28800000, dstSavings = 3600000, useDaylight = true, transitions = 189, lastRule = Java.util.SimpleTimeZone [id = America/Vancouver, offset = -28800000, dstSavings = 3600000, useDaylight = true, startYear = 0, startMode = 3, startMonth = 2, startDay = 8, startDayOfWeek = 1, startTime = 7200000, startTimeMode = 0, endMode = 3, endMonth = 10, endDay = 1, endDayOfWeek = 1, endTime = 7200000, endTimeMode = 0]], firstDayOfWeek = 1, minimalDaysInFirstWeek = 1 YEAR = 1985, MONTH = 4, WEEK_OF_YEAR = ?, WEEK_OF_MONTH = ?, DAY_OF_MONTH = 22, DAY_OF_YEAR = ?, DAY_OF_WEEK =?, DAY_OF_WEEK_IN_MONTH =?, AM_PM = 0, HOUR = 0, HOUR_OF, SEC 0, MILLISECOND = ?, ZONE_OFFSET = ?, DST_OFFSET =?]

Les valeurs year, month et day_of_month sont toutes correctes car ce sont les chiffres que j'ai transmis lors de sa création.

Réflexions, suggestions, suis-je même proche?

Modifier

Les problèmes d'origine ont été résolus (merci assylias!), Mais je ne peux toujours pas imprimer correctement car les deux fonctions ne sont pas liées et les exigences sont d'avoir une valeur de date GregorianCalendar imprimée à partir de l'objet personne (comme date de naissance est un GregorianCalendar).

Code mis à jour:

public class DateUtil {

    static SimpleDateFormat fmt = new SimpleDateFormat("dd-MMM-yyyy");

    public static GregorianCalendar convertFromDMY(String dd_mm_yy) throws ParseException{

        // this actually works, got rid of the original code idea
        String[] splitDate = dd_mm_yy.split("-");
        int days = Integer.parseInt(splitDate[0]);
        int month = (Integer.parseInt(splitDate[1]) - 1);
        int year = Integer.parseInt(splitDate[2]);

        // dates go in properly
        GregorianCalendar dateConverted = new GregorianCalendar(year, month, days);
        String finalDate = format(dateConverted);
        return ;
    }

    public static String format(GregorianCalendar date) throws ParseException{

       fmt.setCalendar(date);
        String dateFormatted = fmt.format(date.getTime());
        System.out.println(dateFormatted);
        return dateFormatted;
    }

}

Dernière modification

OK, il semble donc que je suis un idiot et que je n'ai PAS besoin de lier les deux fonctions DateUtil ensemble, mais utilisez-les en tandem. Tout d'abord, convertissez la date de naissance en GregorianCalendar et stockez-la dans l'objet personne. Ensuite, dans l'instruction print, indiquez simplement au programme de formater cette date lors de son impression. Le problème a été résolu. Tout fonctionne selon les spécifications maintenant, et je me sens beaucoup plus stupide parce que je volais comme un poisson hors de l'eau pendant le dernier jour environ avec la classe DateUtil, essayant de les faire fonctionner en même temps.

Merci pour l'aide à obtenir la date correctement!

28
RejectionHurts

La méthode SimpleDateFormat.format() prend un Date comme paramètre. Vous pouvez obtenir un Date à partir d'un Calendar en appelant sa méthode getTime():

public static String format(GregorianCalendar calendar) {
    SimpleDateFormat fmt = new SimpleDateFormat("dd-MMM-yyyy");
    fmt.setCalendar(calendar);
    String dateFormatted = fmt.format(calendar.getTime());

    return dateFormatted;
}

Notez également que les mois commencent à 0, vous vouliez donc probablement dire:

int month = Integer.parseInt(splitDate[1]) - 1;
48
assylias

Pourquoi de telles complications?

public static GregorianCalendar convertFromDMY(String dd_mm_yy) throws ParseException 
{
    SimpleDateFormat fmt = new SimpleDateFormat("dd-MMM-yyyy");
    Date date = fmt.parse(dd_mm_yy);
    GregorianCalendar cal = GregorianCalendar.getInstance();
    cal.setTime(date);
    return cal;
}
4
m0skit0

Un SimpleDateFormat, comme son nom l'indique, formate Dates. Pas un Calendar. Donc, si vous souhaitez formater un GregorianCalendar à l'aide d'un SimpleDateFormat, vous devez d'abord convertir le Calendar en Date:

dateFormat.format(calendar.getTime());

Et ce que vous voyez imprimé est la représentation toString() du calendrier. Son utilisation prévue est le débogage. Il n'est pas destiné à être utilisé pour afficher une date dans une interface graphique. Pour cela, utilisez un (Simple) DateFormat.

Enfin, pour convertir d'un String en Date, vous devez également utiliser une méthode (Simple) DateFormat (sa méthode parse() ), plutôt que de diviser le String comme vous le faites. Cela vous donnera un objet Date, et vous pouvez créer un Calendar à partir du Date en l'instanciant (Calendar.getInstance()) et en définissant son heure (calendar.setTime()).

Mon conseil serait: googler n'est pas la solution ici. La lecture de la documentation API est ce que vous devez faire.

2
JB Nizet
  1. Vous y mettez une année à deux chiffres. Le premier siècle. Et le calendrier grégorien a commencé au XVIe siècle. Je pense que vous devriez ajouter 2000 à l'année.

  2. Le mois dans la fonction new GregorianCalendar(year, month, days) est basé sur 0. Soustrayez 1 du mois.

  3. Modifiez le corps de la deuxième fonction comme suit:

        String dateFormatted = null;
        SimpleDateFormat fmt = new SimpleDateFormat("dd-MMM-yyyy");
        try {
            dateFormatted = fmt.format(date);
        }
        catch ( IllegalArgumentException e){
            System.out.println(e.getMessage());
        }
        return dateFormatted;
    

Après le débogage, vous verrez que simplement GregorianCalendar ne peut pas être un argument de la fmt.format();.

Vraiment, personne n'a besoin de GregorianCalendar en sortie, même si on vous dit de retourner "une chaîne".

Remplacez l'en-tête de votre fonction de format par

public static String format(final Date date) 

et effectuez les modifications appropriées. fmt.format() prendra volontiers l'objet Date.

  1. Toujours après qu'une exception inattendue se produit, rattrapez-la vous-même, ne laissez pas la machine Java le faire. De cette façon, vous comprendrez le problème.
2
Gangnus

tl; dr

LocalDate.parse(
    "23-Mar-2017" ,
    DateTimeFormatter.ofPattern( "dd-MMM-uuuu" , Locale.US ) 
)

Évitez les anciennes classes de date et d'heure

La question et les autres réponses sont désormais obsolètes, utilisant d'anciennes classes de date-heure gênantes qui sont désormais héritées, supplantées par les classes Java.time.

Utilisation de Java.time

Vous semblez avoir affaire à des valeurs de date uniquement. N'utilisez donc pas de classe date-heure. Utilisez plutôt LocalDate. La classe LocalDate représente une valeur de date uniquement sans heure et sans fuseau horaire.

Spécifiez un Locale pour déterminer (a) la langue humaine pour la traduction du nom du jour, du nom du mois, etc., et (b) les normes culturelles déterminant les questions d'abréviation, de capitalisation , ponctuation, séparateurs, etc.

Analyser une chaîne.

String input = "23-Mar-2017" ;
DateTimeFormatter f = DateTimeFormatter.ofPattern( "dd-MMM-uuuu" , Locale.US ) ;
LocalDate ld = LocalDate.parse( input , f );

Générez une chaîne.

String output = ld.format( f );

Si vous avez reçu des chiffres plutôt que du texte pour l'année, le mois et le jour du mois, utilisez LocalDate.of.

LocalDate ld = LocalDate.of( 2017 , 3 , 23 );  // ( year , month 1-12 , day-of-month )

Voir ceci code exécuté en direct sur IdeOne.com .

entrée: 23 mars 2017

ld.toString (): 2017-03-23

sortie: 23 mars 2017


À propos de Java.time

Le cadre Java.time est intégré à Java 8 et versions ultérieures. Ces classes supplantent l'ancien hérité) gênant classes date-heure telles que Java.util.Date , Calendar , & SimpleDateFormat .

Le projet Joda-Time , maintenant en mode maintenance , conseille la migration vers les classes Java.time .

Pour en savoir plus, consultez le Tutoriel Oracle . Et recherchez Stack Overflow pour de nombreux exemples et explications. La spécification est JSR 31 .

À l'aide d'un pilote JDBC compatible avec JDBC 4.2 ou version ultérieure, vous pouvez échanger des objets Java.time directement avec votre base de données. Pas besoin de chaînes ni de classes Java.sql. *.

Où obtenir les classes Java.time?

Le projet ThreeTen-Extra étend Java.time avec des classes supplémentaires. Ce projet est un terrain d'essai pour de futurs ajouts possibles à Java.time. Vous pouvez trouver ici des classes utiles telles que Interval , YearWeek , YearQuarter , et plus .

2
Basil Bourque