%SUBDT
Extraire un morceau d'une date ou d'une heure
Renvoie sous forme de nombre l'année, le mois, le jour, l'heure, les minutes, les secondes ou les microsecondes contenus dans une date, une heure ou un horodatage.
Syntaxe
%SUBDT(valeur : unité)
valeur- Une date, une heure ou un horodatage.
unité- Le morceau voulu :
*YEARS(*Y),*MONTHS(*M),*DAYS(*D),*HOURS(*H),*MINUTES(*MN),*SECONDS(*S),*MSECONDS(*MS). L'unité doit exister dans le type : pas d'heures dans une date, pas de microsecondes dans une heure. - Résultat
- Un nombre entier, sans zéro à gauche : le mois de mars vaut 3.
À quoi ça sert
Pour trouver le trimestre d'une facture, tester une année bissextile, regrouper des ventes par mois ou par heure de pointage, on a besoin d'un nombre, pas d'une date entière. %SUBDT l'extrait sans découpage de texte.
Exemple 1 : Année, mois, jour, heure...
**free
// %SUBDT : extraire l'annee, le mois, le jour, l'heure... d'une date ou d'un horodatage.
ctl-opt dftactgrp(*no) actgrp(*new);
dcl-s facture date inz(d'2026-03-05');
dcl-s pointage timestamp inz(z'2026-09-30-14.05.30.123456');
dcl-s annee int(10);
dcl-s mois int(10);
annee = %subdt(facture : *years);
mois = %subdt(facture : *months);
snd-msg 'Facture : annee ' + %char(annee) + ', mois ' + %char(mois) +
', jour ' + %char(%subdt(facture : *days));
snd-msg 'Pointage : ' + %char(%subdt(pointage : *hours)) + ' h ' +
%char(%subdt(pointage : *minutes)) + ' min ' +
%char(%subdt(pointage : *seconds)) + ' s';
snd-msg 'Microsecondes : ' + %char(%subdt(pointage : *mseconds));
// Le mois de la facture sert a choisir un trimestre.
snd-msg 'Trimestre : T' + %char(%div(%subdt(facture : *months) - 1 : 3) + 1);
// Annee bissextile (regle simplifiee : annee divisible par 4).
if %rem(%subdt(d'2028-02-01' : *years) : 4) = 0;
snd-msg '2028 est bissextile';
endif;
*inlr = *on;
Résultat réel, compilé et exécuté sur IBM i 7.5 :
Facture : annee 2026, mois 3, jour 5
Pointage : 14 h 5 min 30 s
Microsecondes : 123456
Trimestre : T1
2028 est bissextile
Sur une date : année, mois, jour. Sur un horodatage : heure, minute, seconde et microsecondes (123456). Comme on obtient des nombres, on calcule directement : le trimestre avec %DIV, la parité de l'année avec %REM.
Exemple 2 : Le zéro qui manque
**free
// %SUBDT renvoie un nombre : le mois de mars donne 3, pas 03.
ctl-opt dftactgrp(*no) actgrp(*new);
dcl-s facture date inz(d'2026-03-05');
dcl-s mois zoned(2:0);
// Concatenation directe : pas de zero de tete, le libelle est faux.
snd-msg 'Periode brute : [' + %char(%subdt(facture : *years)) + '-' +
%char(%subdt(facture : *months)) + ']';
// Solution 1 : passer par une zone numerique a 2 chiffres et %EDITC avec le code X.
mois = %subdt(facture : *months);
snd-msg 'Avec %EDITC : [' + %char(%subdt(facture : *years)) + '-' +
%editc(mois : 'X') + ']';
// Solution 2 : ne pas extraire, decouper le texte ISO de la date.
snd-msg 'Avec %SUBST : [' + %subst(%char(facture : *iso) : 1 : 7) + ']';
// Le nombre extrait sert en revanche tres bien aux calculs.
snd-msg 'Cle numerique : ['
+ %char(%subdt(facture : *years) * 100 + %subdt(facture : *months)) + ']';
*inlr = *on;
Résultat réel, compilé et exécuté sur IBM i 7.5 :
Periode brute : [2026-3]
Avec %EDITC : [2026-03]
Avec %SUBST : [2026-03]
Cle numerique : [202603]
Le mois de mars donne 2026-3 quand on concatène directement. Deux solutions : ranger le nombre dans une zone zoned(2:0) et l'éditer avec le code X de %EDITC, ou découper le texte ISO de la date avec %SUBST. Le nombre reste idéal pour un calcul : 202603 est une clé de tri.
Le piège
Le résultat est un nombre : pas de zéro devant. Le mois de mars renvoie 3, et %CHAR(%SUBDT(facture : *MONTHS)) donne 3, pas 03. Pour un libellé 2026-03, passer par une zone zoned(2:0) et %EDITC(zone : 'X'), ou par %SUBST sur %CHAR(date : *ISO).
Deux abréviations se ressemblent : *M désigne les mois, *MN les minutes. Par ailleurs, le compilateur refuse les unités qui n'ont pas de sens (RNF0310 pour *HOURS sur une date, ou pour *MSECONDS sur une heure).