Gatsby - extracting day and month from date field obtained in GraphQL query

Viewed 1077

I'm a newbie web developer working with Gatsby, React, GraphQL and Javascript. I'm working on a simple blog site in which I have some markdown posts whose frontmatter dynamically populate a list of blogposts on a page. I've managed to get this working so far but I wondered how one can work with data obtained from a graphQL query. I'd like to display just the day and month of the post in a stylised way as shown below:

Stylised date

I'm using the following code to pull through the date of the markdown posts:

    const data = useStaticQuery(graphql`
    query{
        allMarkdownRemark{
        edges{
          node{
            frontmatter{
              title
              date
              featuredImage{
                  childImageSharp{
                      fluid{
                        ...GatsbyImageSharpFluid
                      }
                  }
              }
            }
            fields{
                slug
              }
          }
        }
      }
    }
    `)

  return(
        <div id="blog">
            <div class="blog-pad"></div>
            <div class="blog-posts">
            
                {data.allMarkdownRemark.edges.map((edge) =>(
                    <div class="blog-post">
                        <Img fluid={edge.node.frontmatter.featuredImage.childImageSharp.fluid} />
                        <div class="meta">
                            <h3>
                                {edge.node.frontmatter.date}
                            </h3> 
                            <div class="title-date">
                                <h3>
                                    <a href={"/blog/" + edge.node.fields.slug}>{edge.node.frontmatter.title}</a>
                                </h3> 
                                <p>{edge.node.frontmatter.date}</p>  
                                <p>Author</p>  
                            </div>
                        </div>    
                        </div>
                ))}
           
            </div>
            <div class="blog-pad"></div>
        </div>
    )

With a bit of styling added this results in:

My listing

How can I extract just the day and month from this {edge.node.frontmatter.date}? I thought to write a javascript function to do some string formatting on it however I'm not quite sure how to go about writing the function nor how it fits into the context of jsx and graphQL. Would this query called const data get passed as a parameter to the function which would then return a string? return <p>3 Dec</p>

2 Answers

You have multiple approaches to achieve this:

  • Gatsby uses momentjs to format dates on the fly in the GraphQL query using formatString:

      const data = useStaticQuery(graphql`
      query{
          allMarkdownRemark{
          edges{
            node{
              frontmatter{
                title
                date(formatString: "YYYY.MM.DD")
                featuredImage{
                    childImageSharp{
                        fluid{
                          ...GatsbyImageSharpFluid
                        }
                    }
                }
              }
              fields{
                  slug
                }
            }
          }
        }
      }
      `)
    

    You can check for further formatting details in the momentjs docs.

  • If the previous approach doesn't fit your requeriments, you can always format the result using JavaScript + momentjs from the GraphQL response:

       const data = useStaticQuery(graphql`
      query{
          allMarkdownRemark{
          edges{
            node{
              frontmatter{
                title
                date
                featuredImage{
                    childImageSharp{
                        fluid{
                          ...GatsbyImageSharpFluid
                        }
                    }
                }
              }
              fields{
                  slug
                }
            }
          }
        }
      }
      `)
    
    
    const formattedDate= date =>{
      let day, month, year;
    
      day= moment(date).format("DD");
      month= moment(date).format("MM");
      year= moment(date).format("YYYY");
    
      return <div>`${year}.${month}.${day}`</div>
    }
    
    return(
          <div id="blog">
              <div class="blog-pad"></div>
              <div class="blog-posts">
    
                  {data.allMarkdownRemark.edges.map((edge) =>(
                      <div class="blog-post">
                          <Img fluid={edge.node.frontmatter.featuredImage.childImageSharp.fluid} />
                          <div class="meta">
                              <h3>
                               {formattedDate(edge.node.frontmatter.date)}
                              </h3> 
                              <div class="title-date">
                                  <h3>
                                      <a href={"/blog/" + edge.node.fields.slug}>{edge.node.frontmatter.title}</a>
                                  </h3> 
                                  <p>{edge.node.frontmatter.date}</p>  
                                  <p>Author</p>  
                              </div>
                          </div>    
                          </div>
                  ))}
    
              </div>
              <div class="blog-pad"></div>
          </div>
      )
    
    

You can format any date with the desired format using moment(yourDateHere).format(yourFormatHere). Using this approach you will be able to customize more the output and styling, adding HTML tags or removing spaces between dates.

This can be done by defining a function which does simple string formatting outside of your JSX. You can then call your function in the curly brases {myFunction(parameter)} passing the graphQL query data to this function as a parameter.

function dayMonth(data){

    const monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
                        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];

    //split up the string to get the day and month                    
    var month = parseInt(data.slice(5,7));
    var day = data.slice(8,10);

    //remove 0 from 02, 03 etc ... until 10
    if(day[0]=="0"){
        day = day.slice(1,2);
    }

    //concatenate the two together again and return
    var formatted = day + " " + monthNames[month];

    return formatted;
}

const BlogPage = () =>{

    const data = useStaticQuery(graphql`
    query{
        allMarkdownRemark{
        edges{
          node{
            frontmatter{
              title
              date
              featuredImage{
                  childImageSharp{
                      fluid{
                        ...GatsbyImageSharpFluid
                      }
                  }
              }
            }
            fields{
                slug
              }
          }
        }
      }
    }
    `);

    return(
        <div id="blog">
            <div class="blog-pad"></div>
            <div class="blog-posts">
            
                {data.allMarkdownRemark.edges.map((edge) =>(
                    <div class="blog-post">
                        <Img fluid={edge.node.frontmatter.featuredImage.childImageSharp.fluid} />
                        <div class="meta">
                                <h3>
                                {dayMonth(edge.node.frontmatter.date)}
                                </h3>
                            <div class="title-date">
                                <h3>
                                    <a href={"/blog/" + edge.node.fields.slug}>{edge.node.frontmatter.title}</a>
                                </h3> 
                                <p>{edge.node.frontmatter.date}</p>  
                                <p>Author</p>  
                            </div>
                        </div>    
                        </div>
                ))}
           
            </div>
            <div class="blog-pad"></div>
        </div>
    )
}  
Related